diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /dev/null +++ b/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /dev/null +++ b/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +android.useAndroidX=true +android.enableJetifier=true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.0 + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/route/fadeRoute.dart b/lib/ui/widgets/common/route/fadeRoute.dart new file mode 100644 index 0000000..09cda1e --- /dev/null +++ b/lib/ui/widgets/common/route/fadeRoute.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; + +///FadeRoute是自定义的切换过度动画(渐隐渐现) +class FadeRoute extends PageRouteBuilder { + final Widget page; + FadeRoute({this.page}): super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) =>page,transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) =>FadeTransition( + opacity: animation, + child: child, + ), + ); +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/route/fadeRoute.dart b/lib/ui/widgets/common/route/fadeRoute.dart new file mode 100644 index 0000000..09cda1e --- /dev/null +++ b/lib/ui/widgets/common/route/fadeRoute.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; + +///FadeRoute是自定义的切换过度动画(渐隐渐现) +class FadeRoute extends PageRouteBuilder { + final Widget page; + FadeRoute({this.page}): super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) =>page,transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) =>FadeTransition( + opacity: animation, + child: child, + ), + ); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/route/popRoute.dart b/lib/ui/widgets/common/route/popRoute.dart new file mode 100644 index 0000000..e779cd1 --- /dev/null +++ b/lib/ui/widgets/common/route/popRoute.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class PopRoute extends PopupRoute{ + final Duration _duration = Duration(milliseconds: 300); + Widget child; + + PopRoute({@required this.child}); + + @override + Color get barrierColor => null; + + @override + bool get barrierDismissible => true; + + @override + String get barrierLabel => null; + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + return child; + } + + @override + Duration get transitionDuration => _duration; + +} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/route/fadeRoute.dart b/lib/ui/widgets/common/route/fadeRoute.dart new file mode 100644 index 0000000..09cda1e --- /dev/null +++ b/lib/ui/widgets/common/route/fadeRoute.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; + +///FadeRoute是自定义的切换过度动画(渐隐渐现) +class FadeRoute extends PageRouteBuilder { + final Widget page; + FadeRoute({this.page}): super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) =>page,transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) =>FadeTransition( + opacity: animation, + child: child, + ), + ); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/route/popRoute.dart b/lib/ui/widgets/common/route/popRoute.dart new file mode 100644 index 0000000..e779cd1 --- /dev/null +++ b/lib/ui/widgets/common/route/popRoute.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class PopRoute extends PopupRoute{ + final Duration _duration = Duration(milliseconds: 300); + Widget child; + + PopRoute({@required this.child}); + + @override + Color get barrierColor => null; + + @override + bool get barrierDismissible => true; + + @override + String get barrierLabel => null; + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + return child; + } + + @override + Duration get transitionDuration => _duration; + +} \ No newline at end of file diff --git a/lib/ui/widgets/common/web_scaffold.dart b/lib/ui/widgets/common/web_scaffold.dart new file mode 100644 index 0000000..3c7efe2 --- /dev/null +++ b/lib/ui/widgets/common/web_scaffold.dart @@ -0,0 +1,173 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; +import 'package:share/share.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +import 'button/likebtn/like_button.dart'; + +class WebScaffold extends StatefulWidget { + const WebScaffold({ + Key key, + this.title, + this.titleId, + this.url, + }) : super(key: key); + + final String title; + final String titleId; + final String url; + + @override + State createState() { + return new WebScaffoldState(); + } +} + +class WebScaffoldState extends State { +// WebViewController _webViewController; +// bool _isShowFloatBtn = false; + + void _onPopSelected(String value) { + String _title = widget.title ?? IntlUtil.getString(context, widget.titleId); + switch (value) { + case "browser": // 浏览 + NavigatorUtil.launchInBrowser(widget.url, title: _title); + break; + case "collection": // 收藏 + break; + case "share": // 分享 + String _url = widget.url; + Share.share('$_title : $_url'); + break; + default: + break; + } + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + centerTitle: true, + actions: [ + LikeButton( + width: 56.0, + duration: Duration(milliseconds: 500), + ), +// new IconButton(icon: new Icon(Icons.more_vert), onPressed: () {}), + new PopupMenuButton( + padding: const EdgeInsets.all(0.0), + onSelected: _onPopSelected, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: "browser", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '浏览器打开', + style: TextStyles.listContent, + ) + ], + ), + ))), +// new PopupMenuItem( +// value: "collection", +// child: ListTile( +// contentPadding: EdgeInsets.all(0.0), +// dense: false, +// title: new Container( +// alignment: Alignment.center, +// child: new Row( +// children: [ +// Icon( +// Icons.collections, +// color: Colours.gray_66, +// size: 22.0, +// ), +// Gaps.hGap10, +// Text( +// '收藏', +// style: TextStyles.listContent, +// ) +// ], +// ), +// ))), + new PopupMenuItem( + value: "share", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.share, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '分享', + style: TextStyles.listContent, + ) + ], + ), + ))), + ]) + ], + ), + body: new WebView( + onWebViewCreated: (WebViewController webViewController) { +// _webViewController = webViewController; +// _webViewController.addListener(() { +// int _scrollY = _webViewController.scrollY.toInt(); +// if (_scrollY < 480 && _isShowFloatBtn) { +// _isShowFloatBtn = false; +// setState(() {}); +// } else if (_scrollY > 480 && !_isShowFloatBtn) { +// _isShowFloatBtn = true; +// setState(() {}); +// } +// }); + }, + initialUrl: widget.url, + javascriptMode: JavascriptMode.unrestricted, + ), +// floatingActionButton: _buildFloatingActionButton(), + ); + } + +// Widget _buildFloatingActionButton() { +// if (_webViewController == null || _webViewController.scrollY < 480) { +// return null; +// } +// return new FloatingActionButton( +// heroTag: widget.title ?? widget.titleId, +// backgroundColor: Theme.of(context).primaryColor, +// child: Icon( +// Icons.keyboard_arrow_up, +// ), +// onPressed: () { +// _webViewController.scrollTop(); +// }); +// } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/route/fadeRoute.dart b/lib/ui/widgets/common/route/fadeRoute.dart new file mode 100644 index 0000000..09cda1e --- /dev/null +++ b/lib/ui/widgets/common/route/fadeRoute.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; + +///FadeRoute是自定义的切换过度动画(渐隐渐现) +class FadeRoute extends PageRouteBuilder { + final Widget page; + FadeRoute({this.page}): super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) =>page,transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) =>FadeTransition( + opacity: animation, + child: child, + ), + ); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/route/popRoute.dart b/lib/ui/widgets/common/route/popRoute.dart new file mode 100644 index 0000000..e779cd1 --- /dev/null +++ b/lib/ui/widgets/common/route/popRoute.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class PopRoute extends PopupRoute{ + final Duration _duration = Duration(milliseconds: 300); + Widget child; + + PopRoute({@required this.child}); + + @override + Color get barrierColor => null; + + @override + bool get barrierDismissible => true; + + @override + String get barrierLabel => null; + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + return child; + } + + @override + Duration get transitionDuration => _duration; + +} \ No newline at end of file diff --git a/lib/ui/widgets/common/web_scaffold.dart b/lib/ui/widgets/common/web_scaffold.dart new file mode 100644 index 0000000..3c7efe2 --- /dev/null +++ b/lib/ui/widgets/common/web_scaffold.dart @@ -0,0 +1,173 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; +import 'package:share/share.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +import 'button/likebtn/like_button.dart'; + +class WebScaffold extends StatefulWidget { + const WebScaffold({ + Key key, + this.title, + this.titleId, + this.url, + }) : super(key: key); + + final String title; + final String titleId; + final String url; + + @override + State createState() { + return new WebScaffoldState(); + } +} + +class WebScaffoldState extends State { +// WebViewController _webViewController; +// bool _isShowFloatBtn = false; + + void _onPopSelected(String value) { + String _title = widget.title ?? IntlUtil.getString(context, widget.titleId); + switch (value) { + case "browser": // 浏览 + NavigatorUtil.launchInBrowser(widget.url, title: _title); + break; + case "collection": // 收藏 + break; + case "share": // 分享 + String _url = widget.url; + Share.share('$_title : $_url'); + break; + default: + break; + } + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + centerTitle: true, + actions: [ + LikeButton( + width: 56.0, + duration: Duration(milliseconds: 500), + ), +// new IconButton(icon: new Icon(Icons.more_vert), onPressed: () {}), + new PopupMenuButton( + padding: const EdgeInsets.all(0.0), + onSelected: _onPopSelected, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: "browser", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '浏览器打开', + style: TextStyles.listContent, + ) + ], + ), + ))), +// new PopupMenuItem( +// value: "collection", +// child: ListTile( +// contentPadding: EdgeInsets.all(0.0), +// dense: false, +// title: new Container( +// alignment: Alignment.center, +// child: new Row( +// children: [ +// Icon( +// Icons.collections, +// color: Colours.gray_66, +// size: 22.0, +// ), +// Gaps.hGap10, +// Text( +// '收藏', +// style: TextStyles.listContent, +// ) +// ], +// ), +// ))), + new PopupMenuItem( + value: "share", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.share, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '分享', + style: TextStyles.listContent, + ) + ], + ), + ))), + ]) + ], + ), + body: new WebView( + onWebViewCreated: (WebViewController webViewController) { +// _webViewController = webViewController; +// _webViewController.addListener(() { +// int _scrollY = _webViewController.scrollY.toInt(); +// if (_scrollY < 480 && _isShowFloatBtn) { +// _isShowFloatBtn = false; +// setState(() {}); +// } else if (_scrollY > 480 && !_isShowFloatBtn) { +// _isShowFloatBtn = true; +// setState(() {}); +// } +// }); + }, + initialUrl: widget.url, + javascriptMode: JavascriptMode.unrestricted, + ), +// floatingActionButton: _buildFloatingActionButton(), + ); + } + +// Widget _buildFloatingActionButton() { +// if (_webViewController == null || _webViewController.scrollY < 480) { +// return null; +// } +// return new FloatingActionButton( +// heroTag: widget.title ?? widget.titleId, +// backgroundColor: Theme.of(context).primaryColor, +// child: Icon( +// Icons.keyboard_arrow_up, +// ), +// onPressed: () { +// _webViewController.scrollTop(); +// }); +// } +} diff --git a/lib/ui/widgets/login_page/login_item_widget.dart b/lib/ui/widgets/login_page/login_item_widget.dart new file mode 100644 index 0000000..58a8778 --- /dev/null +++ b/lib/ui/widgets/login_page/login_item_widget.dart @@ -0,0 +1,96 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 登录项 +class LoginItem extends StatefulWidget { + final IconData prefixIcon; // 前方icon + final bool hasSuffixIcon; // 是否要后面的icon + final String hintText; // 提示文字 + final bool autoFocus; // 自动聚焦 + final TextInputType keyboardType; // 键盘类型 + final int maxLength; // 最大程度 + final bool maxLengthEnforced; // 当长度达到限制长度时,是否强制组织输入 + final TextInputAction textInputAction; // 输入action + final TextEditingController controller; // controller + final FocusNode focusNode; //focusNode + final VoidCallback onEditingComplete; // 输入完毕后的回调 + + const LoginItem( + {Key key, + this.prefixIcon, + this.hasSuffixIcon = false, + this.autoFocus = false, + this.keyboardType = TextInputType.text, + this.hintText, + this.maxLength, + this.maxLengthEnforced = true, + this.textInputAction, + this.controller, + this.focusNode, + this.onEditingComplete}) + : super(key: key); + + @override + State createState() { + return LoginItemState(); + } +} + +class LoginItemState extends State { + bool _obscureText; // 是否隐藏原始文字 // 密码用 + + @override + void initState() { + super.initState(); + _obscureText = widget.hasSuffixIcon; + } + + @override + Widget build(BuildContext context) { + return new Row( + children: [ + new IconButton( + iconSize: 28, + icon: new Icon( + widget.prefixIcon, + color: Theme.of(context).primaryColor, + ), + onPressed: () {}), + Gaps.hGap5, + new Expanded( + child: new TextField( + textInputAction: widget.textInputAction, + focusNode: widget.focusNode, + onEditingComplete: widget.onEditingComplete, + obscureText: _obscureText, + controller: widget.controller, + maxLength: widget.maxLength, + maxLengthEnforced: widget.maxLengthEnforced, + style: new TextStyle(color: Colours.gray_66, fontSize: 14), + decoration: new InputDecoration( + hintText: widget.hintText, + hintStyle: new TextStyle(color: Colours.gray_99, fontSize: 14), + suffixIcon: widget.hasSuffixIcon + ? new IconButton( + icon: new Icon( + _obscureText + ? Icons.visibility + : Icons.visibility_off, + color: Colours.gray_66, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }) + : null, + focusedBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + enabledBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + )), + ), + ], + ); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/route/fadeRoute.dart b/lib/ui/widgets/common/route/fadeRoute.dart new file mode 100644 index 0000000..09cda1e --- /dev/null +++ b/lib/ui/widgets/common/route/fadeRoute.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; + +///FadeRoute是自定义的切换过度动画(渐隐渐现) +class FadeRoute extends PageRouteBuilder { + final Widget page; + FadeRoute({this.page}): super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) =>page,transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) =>FadeTransition( + opacity: animation, + child: child, + ), + ); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/route/popRoute.dart b/lib/ui/widgets/common/route/popRoute.dart new file mode 100644 index 0000000..e779cd1 --- /dev/null +++ b/lib/ui/widgets/common/route/popRoute.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class PopRoute extends PopupRoute{ + final Duration _duration = Duration(milliseconds: 300); + Widget child; + + PopRoute({@required this.child}); + + @override + Color get barrierColor => null; + + @override + bool get barrierDismissible => true; + + @override + String get barrierLabel => null; + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + return child; + } + + @override + Duration get transitionDuration => _duration; + +} \ No newline at end of file diff --git a/lib/ui/widgets/common/web_scaffold.dart b/lib/ui/widgets/common/web_scaffold.dart new file mode 100644 index 0000000..3c7efe2 --- /dev/null +++ b/lib/ui/widgets/common/web_scaffold.dart @@ -0,0 +1,173 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; +import 'package:share/share.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +import 'button/likebtn/like_button.dart'; + +class WebScaffold extends StatefulWidget { + const WebScaffold({ + Key key, + this.title, + this.titleId, + this.url, + }) : super(key: key); + + final String title; + final String titleId; + final String url; + + @override + State createState() { + return new WebScaffoldState(); + } +} + +class WebScaffoldState extends State { +// WebViewController _webViewController; +// bool _isShowFloatBtn = false; + + void _onPopSelected(String value) { + String _title = widget.title ?? IntlUtil.getString(context, widget.titleId); + switch (value) { + case "browser": // 浏览 + NavigatorUtil.launchInBrowser(widget.url, title: _title); + break; + case "collection": // 收藏 + break; + case "share": // 分享 + String _url = widget.url; + Share.share('$_title : $_url'); + break; + default: + break; + } + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + centerTitle: true, + actions: [ + LikeButton( + width: 56.0, + duration: Duration(milliseconds: 500), + ), +// new IconButton(icon: new Icon(Icons.more_vert), onPressed: () {}), + new PopupMenuButton( + padding: const EdgeInsets.all(0.0), + onSelected: _onPopSelected, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: "browser", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '浏览器打开', + style: TextStyles.listContent, + ) + ], + ), + ))), +// new PopupMenuItem( +// value: "collection", +// child: ListTile( +// contentPadding: EdgeInsets.all(0.0), +// dense: false, +// title: new Container( +// alignment: Alignment.center, +// child: new Row( +// children: [ +// Icon( +// Icons.collections, +// color: Colours.gray_66, +// size: 22.0, +// ), +// Gaps.hGap10, +// Text( +// '收藏', +// style: TextStyles.listContent, +// ) +// ], +// ), +// ))), + new PopupMenuItem( + value: "share", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.share, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '分享', + style: TextStyles.listContent, + ) + ], + ), + ))), + ]) + ], + ), + body: new WebView( + onWebViewCreated: (WebViewController webViewController) { +// _webViewController = webViewController; +// _webViewController.addListener(() { +// int _scrollY = _webViewController.scrollY.toInt(); +// if (_scrollY < 480 && _isShowFloatBtn) { +// _isShowFloatBtn = false; +// setState(() {}); +// } else if (_scrollY > 480 && !_isShowFloatBtn) { +// _isShowFloatBtn = true; +// setState(() {}); +// } +// }); + }, + initialUrl: widget.url, + javascriptMode: JavascriptMode.unrestricted, + ), +// floatingActionButton: _buildFloatingActionButton(), + ); + } + +// Widget _buildFloatingActionButton() { +// if (_webViewController == null || _webViewController.scrollY < 480) { +// return null; +// } +// return new FloatingActionButton( +// heroTag: widget.title ?? widget.titleId, +// backgroundColor: Theme.of(context).primaryColor, +// child: Icon( +// Icons.keyboard_arrow_up, +// ), +// onPressed: () { +// _webViewController.scrollTop(); +// }); +// } +} diff --git a/lib/ui/widgets/login_page/login_item_widget.dart b/lib/ui/widgets/login_page/login_item_widget.dart new file mode 100644 index 0000000..58a8778 --- /dev/null +++ b/lib/ui/widgets/login_page/login_item_widget.dart @@ -0,0 +1,96 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 登录项 +class LoginItem extends StatefulWidget { + final IconData prefixIcon; // 前方icon + final bool hasSuffixIcon; // 是否要后面的icon + final String hintText; // 提示文字 + final bool autoFocus; // 自动聚焦 + final TextInputType keyboardType; // 键盘类型 + final int maxLength; // 最大程度 + final bool maxLengthEnforced; // 当长度达到限制长度时,是否强制组织输入 + final TextInputAction textInputAction; // 输入action + final TextEditingController controller; // controller + final FocusNode focusNode; //focusNode + final VoidCallback onEditingComplete; // 输入完毕后的回调 + + const LoginItem( + {Key key, + this.prefixIcon, + this.hasSuffixIcon = false, + this.autoFocus = false, + this.keyboardType = TextInputType.text, + this.hintText, + this.maxLength, + this.maxLengthEnforced = true, + this.textInputAction, + this.controller, + this.focusNode, + this.onEditingComplete}) + : super(key: key); + + @override + State createState() { + return LoginItemState(); + } +} + +class LoginItemState extends State { + bool _obscureText; // 是否隐藏原始文字 // 密码用 + + @override + void initState() { + super.initState(); + _obscureText = widget.hasSuffixIcon; + } + + @override + Widget build(BuildContext context) { + return new Row( + children: [ + new IconButton( + iconSize: 28, + icon: new Icon( + widget.prefixIcon, + color: Theme.of(context).primaryColor, + ), + onPressed: () {}), + Gaps.hGap5, + new Expanded( + child: new TextField( + textInputAction: widget.textInputAction, + focusNode: widget.focusNode, + onEditingComplete: widget.onEditingComplete, + obscureText: _obscureText, + controller: widget.controller, + maxLength: widget.maxLength, + maxLengthEnforced: widget.maxLengthEnforced, + style: new TextStyle(color: Colours.gray_66, fontSize: 14), + decoration: new InputDecoration( + hintText: widget.hintText, + hintStyle: new TextStyle(color: Colours.gray_99, fontSize: 14), + suffixIcon: widget.hasSuffixIcon + ? new IconButton( + icon: new Icon( + _obscureText + ? Icons.visibility + : Icons.visibility_off, + color: Colours.gray_66, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }) + : null, + focusedBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + enabledBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + )), + ), + ], + ); + } +} diff --git a/lib/utils/encrypt_helper.dart b/lib/utils/encrypt_helper.dart new file mode 100644 index 0000000..caf7196 --- /dev/null +++ b/lib/utils/encrypt_helper.dart @@ -0,0 +1,30 @@ +import 'package:encrypt/encrypt.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +import 'dart:async'; +import 'package:flutter/services.dart' show rootBundle; + +/// RSA加密工具 +final parser = RSAKeyParser(); + +class EncryptHelper { + /// 加密 + ///[src] 待加密字符串 + static Future encode(String src) async { + String publicKeyString = await rootBundle.loadString('keys/public_key.pem'); + RSAPublicKey publicKey = parser.parse(publicKeyString); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + return encrypter.encrypt(src).base64; + } + + /// 解密 + /// [decoded] 待解密字符串 + static Future decode(String decoded) async { + String privateKeyString = + await rootBundle.loadString('keys/private_key.pem'); + + final privateKey = parser.parse(privateKeyString); + + final encrypter = Encrypter(RSA(privateKey: privateKey)); + return encrypter.decrypt(Encrypted.fromBase64(decoded)); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/route/fadeRoute.dart b/lib/ui/widgets/common/route/fadeRoute.dart new file mode 100644 index 0000000..09cda1e --- /dev/null +++ b/lib/ui/widgets/common/route/fadeRoute.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; + +///FadeRoute是自定义的切换过度动画(渐隐渐现) +class FadeRoute extends PageRouteBuilder { + final Widget page; + FadeRoute({this.page}): super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) =>page,transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) =>FadeTransition( + opacity: animation, + child: child, + ), + ); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/route/popRoute.dart b/lib/ui/widgets/common/route/popRoute.dart new file mode 100644 index 0000000..e779cd1 --- /dev/null +++ b/lib/ui/widgets/common/route/popRoute.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class PopRoute extends PopupRoute{ + final Duration _duration = Duration(milliseconds: 300); + Widget child; + + PopRoute({@required this.child}); + + @override + Color get barrierColor => null; + + @override + bool get barrierDismissible => true; + + @override + String get barrierLabel => null; + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + return child; + } + + @override + Duration get transitionDuration => _duration; + +} \ No newline at end of file diff --git a/lib/ui/widgets/common/web_scaffold.dart b/lib/ui/widgets/common/web_scaffold.dart new file mode 100644 index 0000000..3c7efe2 --- /dev/null +++ b/lib/ui/widgets/common/web_scaffold.dart @@ -0,0 +1,173 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; +import 'package:share/share.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +import 'button/likebtn/like_button.dart'; + +class WebScaffold extends StatefulWidget { + const WebScaffold({ + Key key, + this.title, + this.titleId, + this.url, + }) : super(key: key); + + final String title; + final String titleId; + final String url; + + @override + State createState() { + return new WebScaffoldState(); + } +} + +class WebScaffoldState extends State { +// WebViewController _webViewController; +// bool _isShowFloatBtn = false; + + void _onPopSelected(String value) { + String _title = widget.title ?? IntlUtil.getString(context, widget.titleId); + switch (value) { + case "browser": // 浏览 + NavigatorUtil.launchInBrowser(widget.url, title: _title); + break; + case "collection": // 收藏 + break; + case "share": // 分享 + String _url = widget.url; + Share.share('$_title : $_url'); + break; + default: + break; + } + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + centerTitle: true, + actions: [ + LikeButton( + width: 56.0, + duration: Duration(milliseconds: 500), + ), +// new IconButton(icon: new Icon(Icons.more_vert), onPressed: () {}), + new PopupMenuButton( + padding: const EdgeInsets.all(0.0), + onSelected: _onPopSelected, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: "browser", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '浏览器打开', + style: TextStyles.listContent, + ) + ], + ), + ))), +// new PopupMenuItem( +// value: "collection", +// child: ListTile( +// contentPadding: EdgeInsets.all(0.0), +// dense: false, +// title: new Container( +// alignment: Alignment.center, +// child: new Row( +// children: [ +// Icon( +// Icons.collections, +// color: Colours.gray_66, +// size: 22.0, +// ), +// Gaps.hGap10, +// Text( +// '收藏', +// style: TextStyles.listContent, +// ) +// ], +// ), +// ))), + new PopupMenuItem( + value: "share", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.share, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '分享', + style: TextStyles.listContent, + ) + ], + ), + ))), + ]) + ], + ), + body: new WebView( + onWebViewCreated: (WebViewController webViewController) { +// _webViewController = webViewController; +// _webViewController.addListener(() { +// int _scrollY = _webViewController.scrollY.toInt(); +// if (_scrollY < 480 && _isShowFloatBtn) { +// _isShowFloatBtn = false; +// setState(() {}); +// } else if (_scrollY > 480 && !_isShowFloatBtn) { +// _isShowFloatBtn = true; +// setState(() {}); +// } +// }); + }, + initialUrl: widget.url, + javascriptMode: JavascriptMode.unrestricted, + ), +// floatingActionButton: _buildFloatingActionButton(), + ); + } + +// Widget _buildFloatingActionButton() { +// if (_webViewController == null || _webViewController.scrollY < 480) { +// return null; +// } +// return new FloatingActionButton( +// heroTag: widget.title ?? widget.titleId, +// backgroundColor: Theme.of(context).primaryColor, +// child: Icon( +// Icons.keyboard_arrow_up, +// ), +// onPressed: () { +// _webViewController.scrollTop(); +// }); +// } +} diff --git a/lib/ui/widgets/login_page/login_item_widget.dart b/lib/ui/widgets/login_page/login_item_widget.dart new file mode 100644 index 0000000..58a8778 --- /dev/null +++ b/lib/ui/widgets/login_page/login_item_widget.dart @@ -0,0 +1,96 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 登录项 +class LoginItem extends StatefulWidget { + final IconData prefixIcon; // 前方icon + final bool hasSuffixIcon; // 是否要后面的icon + final String hintText; // 提示文字 + final bool autoFocus; // 自动聚焦 + final TextInputType keyboardType; // 键盘类型 + final int maxLength; // 最大程度 + final bool maxLengthEnforced; // 当长度达到限制长度时,是否强制组织输入 + final TextInputAction textInputAction; // 输入action + final TextEditingController controller; // controller + final FocusNode focusNode; //focusNode + final VoidCallback onEditingComplete; // 输入完毕后的回调 + + const LoginItem( + {Key key, + this.prefixIcon, + this.hasSuffixIcon = false, + this.autoFocus = false, + this.keyboardType = TextInputType.text, + this.hintText, + this.maxLength, + this.maxLengthEnforced = true, + this.textInputAction, + this.controller, + this.focusNode, + this.onEditingComplete}) + : super(key: key); + + @override + State createState() { + return LoginItemState(); + } +} + +class LoginItemState extends State { + bool _obscureText; // 是否隐藏原始文字 // 密码用 + + @override + void initState() { + super.initState(); + _obscureText = widget.hasSuffixIcon; + } + + @override + Widget build(BuildContext context) { + return new Row( + children: [ + new IconButton( + iconSize: 28, + icon: new Icon( + widget.prefixIcon, + color: Theme.of(context).primaryColor, + ), + onPressed: () {}), + Gaps.hGap5, + new Expanded( + child: new TextField( + textInputAction: widget.textInputAction, + focusNode: widget.focusNode, + onEditingComplete: widget.onEditingComplete, + obscureText: _obscureText, + controller: widget.controller, + maxLength: widget.maxLength, + maxLengthEnforced: widget.maxLengthEnforced, + style: new TextStyle(color: Colours.gray_66, fontSize: 14), + decoration: new InputDecoration( + hintText: widget.hintText, + hintStyle: new TextStyle(color: Colours.gray_99, fontSize: 14), + suffixIcon: widget.hasSuffixIcon + ? new IconButton( + icon: new Icon( + _obscureText + ? Icons.visibility + : Icons.visibility_off, + color: Colours.gray_66, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }) + : null, + focusedBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + enabledBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + )), + ), + ], + ); + } +} diff --git a/lib/utils/encrypt_helper.dart b/lib/utils/encrypt_helper.dart new file mode 100644 index 0000000..caf7196 --- /dev/null +++ b/lib/utils/encrypt_helper.dart @@ -0,0 +1,30 @@ +import 'package:encrypt/encrypt.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +import 'dart:async'; +import 'package:flutter/services.dart' show rootBundle; + +/// RSA加密工具 +final parser = RSAKeyParser(); + +class EncryptHelper { + /// 加密 + ///[src] 待加密字符串 + static Future encode(String src) async { + String publicKeyString = await rootBundle.loadString('keys/public_key.pem'); + RSAPublicKey publicKey = parser.parse(publicKeyString); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + return encrypter.encrypt(src).base64; + } + + /// 解密 + /// [decoded] 待解密字符串 + static Future decode(String decoded) async { + String privateKeyString = + await rootBundle.loadString('keys/private_key.pem'); + + final privateKey = parser.parse(privateKeyString); + + final encrypter = Encrypter(RSA(privateKey: privateKey)); + return encrypter.decrypt(Encrypted.fromBase64(decoded)); + } +} diff --git a/lib/utils/http_utils.dart b/lib/utils/http_utils.dart new file mode 100644 index 0000000..319ca63 --- /dev/null +++ b/lib/utils/http_utils.dart @@ -0,0 +1,30 @@ +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/models/common/version_model.dart'; + +/// 模拟网络请求数据 +class HttpUtils { + Future getSplash() { + return Future.delayed(Duration(milliseconds: 500), () { + return SplashModel( + title: 'Flutter 常用工具类库', + content: 'Flutter 常用工具类库', + url: 'https://www.jianshu.com/p/425a7ff9d66e', + imgUrl: + 'https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_common_utils_a.png', + ); + }); + } + + /// 该地址可能无法下载,请自行更换可测试apk地址。 + Future getVersion() async { + return Future.delayed(Duration(milliseconds: 500), () { + return VersionModel( + title: '有新版本v1.1.0,快去更新吧!', + content: '1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~', + url: + 'https://raw.githubusercontent.com/Sky24n/Doc/master/apks/flutter_wanandroid.apk', + version: '1.0.0', + ); + }); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/route/fadeRoute.dart b/lib/ui/widgets/common/route/fadeRoute.dart new file mode 100644 index 0000000..09cda1e --- /dev/null +++ b/lib/ui/widgets/common/route/fadeRoute.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; + +///FadeRoute是自定义的切换过度动画(渐隐渐现) +class FadeRoute extends PageRouteBuilder { + final Widget page; + FadeRoute({this.page}): super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) =>page,transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) =>FadeTransition( + opacity: animation, + child: child, + ), + ); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/route/popRoute.dart b/lib/ui/widgets/common/route/popRoute.dart new file mode 100644 index 0000000..e779cd1 --- /dev/null +++ b/lib/ui/widgets/common/route/popRoute.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class PopRoute extends PopupRoute{ + final Duration _duration = Duration(milliseconds: 300); + Widget child; + + PopRoute({@required this.child}); + + @override + Color get barrierColor => null; + + @override + bool get barrierDismissible => true; + + @override + String get barrierLabel => null; + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + return child; + } + + @override + Duration get transitionDuration => _duration; + +} \ No newline at end of file diff --git a/lib/ui/widgets/common/web_scaffold.dart b/lib/ui/widgets/common/web_scaffold.dart new file mode 100644 index 0000000..3c7efe2 --- /dev/null +++ b/lib/ui/widgets/common/web_scaffold.dart @@ -0,0 +1,173 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; +import 'package:share/share.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +import 'button/likebtn/like_button.dart'; + +class WebScaffold extends StatefulWidget { + const WebScaffold({ + Key key, + this.title, + this.titleId, + this.url, + }) : super(key: key); + + final String title; + final String titleId; + final String url; + + @override + State createState() { + return new WebScaffoldState(); + } +} + +class WebScaffoldState extends State { +// WebViewController _webViewController; +// bool _isShowFloatBtn = false; + + void _onPopSelected(String value) { + String _title = widget.title ?? IntlUtil.getString(context, widget.titleId); + switch (value) { + case "browser": // 浏览 + NavigatorUtil.launchInBrowser(widget.url, title: _title); + break; + case "collection": // 收藏 + break; + case "share": // 分享 + String _url = widget.url; + Share.share('$_title : $_url'); + break; + default: + break; + } + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + centerTitle: true, + actions: [ + LikeButton( + width: 56.0, + duration: Duration(milliseconds: 500), + ), +// new IconButton(icon: new Icon(Icons.more_vert), onPressed: () {}), + new PopupMenuButton( + padding: const EdgeInsets.all(0.0), + onSelected: _onPopSelected, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: "browser", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '浏览器打开', + style: TextStyles.listContent, + ) + ], + ), + ))), +// new PopupMenuItem( +// value: "collection", +// child: ListTile( +// contentPadding: EdgeInsets.all(0.0), +// dense: false, +// title: new Container( +// alignment: Alignment.center, +// child: new Row( +// children: [ +// Icon( +// Icons.collections, +// color: Colours.gray_66, +// size: 22.0, +// ), +// Gaps.hGap10, +// Text( +// '收藏', +// style: TextStyles.listContent, +// ) +// ], +// ), +// ))), + new PopupMenuItem( + value: "share", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.share, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '分享', + style: TextStyles.listContent, + ) + ], + ), + ))), + ]) + ], + ), + body: new WebView( + onWebViewCreated: (WebViewController webViewController) { +// _webViewController = webViewController; +// _webViewController.addListener(() { +// int _scrollY = _webViewController.scrollY.toInt(); +// if (_scrollY < 480 && _isShowFloatBtn) { +// _isShowFloatBtn = false; +// setState(() {}); +// } else if (_scrollY > 480 && !_isShowFloatBtn) { +// _isShowFloatBtn = true; +// setState(() {}); +// } +// }); + }, + initialUrl: widget.url, + javascriptMode: JavascriptMode.unrestricted, + ), +// floatingActionButton: _buildFloatingActionButton(), + ); + } + +// Widget _buildFloatingActionButton() { +// if (_webViewController == null || _webViewController.scrollY < 480) { +// return null; +// } +// return new FloatingActionButton( +// heroTag: widget.title ?? widget.titleId, +// backgroundColor: Theme.of(context).primaryColor, +// child: Icon( +// Icons.keyboard_arrow_up, +// ), +// onPressed: () { +// _webViewController.scrollTop(); +// }); +// } +} diff --git a/lib/ui/widgets/login_page/login_item_widget.dart b/lib/ui/widgets/login_page/login_item_widget.dart new file mode 100644 index 0000000..58a8778 --- /dev/null +++ b/lib/ui/widgets/login_page/login_item_widget.dart @@ -0,0 +1,96 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 登录项 +class LoginItem extends StatefulWidget { + final IconData prefixIcon; // 前方icon + final bool hasSuffixIcon; // 是否要后面的icon + final String hintText; // 提示文字 + final bool autoFocus; // 自动聚焦 + final TextInputType keyboardType; // 键盘类型 + final int maxLength; // 最大程度 + final bool maxLengthEnforced; // 当长度达到限制长度时,是否强制组织输入 + final TextInputAction textInputAction; // 输入action + final TextEditingController controller; // controller + final FocusNode focusNode; //focusNode + final VoidCallback onEditingComplete; // 输入完毕后的回调 + + const LoginItem( + {Key key, + this.prefixIcon, + this.hasSuffixIcon = false, + this.autoFocus = false, + this.keyboardType = TextInputType.text, + this.hintText, + this.maxLength, + this.maxLengthEnforced = true, + this.textInputAction, + this.controller, + this.focusNode, + this.onEditingComplete}) + : super(key: key); + + @override + State createState() { + return LoginItemState(); + } +} + +class LoginItemState extends State { + bool _obscureText; // 是否隐藏原始文字 // 密码用 + + @override + void initState() { + super.initState(); + _obscureText = widget.hasSuffixIcon; + } + + @override + Widget build(BuildContext context) { + return new Row( + children: [ + new IconButton( + iconSize: 28, + icon: new Icon( + widget.prefixIcon, + color: Theme.of(context).primaryColor, + ), + onPressed: () {}), + Gaps.hGap5, + new Expanded( + child: new TextField( + textInputAction: widget.textInputAction, + focusNode: widget.focusNode, + onEditingComplete: widget.onEditingComplete, + obscureText: _obscureText, + controller: widget.controller, + maxLength: widget.maxLength, + maxLengthEnforced: widget.maxLengthEnforced, + style: new TextStyle(color: Colours.gray_66, fontSize: 14), + decoration: new InputDecoration( + hintText: widget.hintText, + hintStyle: new TextStyle(color: Colours.gray_99, fontSize: 14), + suffixIcon: widget.hasSuffixIcon + ? new IconButton( + icon: new Icon( + _obscureText + ? Icons.visibility + : Icons.visibility_off, + color: Colours.gray_66, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }) + : null, + focusedBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + enabledBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + )), + ), + ], + ); + } +} diff --git a/lib/utils/encrypt_helper.dart b/lib/utils/encrypt_helper.dart new file mode 100644 index 0000000..caf7196 --- /dev/null +++ b/lib/utils/encrypt_helper.dart @@ -0,0 +1,30 @@ +import 'package:encrypt/encrypt.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +import 'dart:async'; +import 'package:flutter/services.dart' show rootBundle; + +/// RSA加密工具 +final parser = RSAKeyParser(); + +class EncryptHelper { + /// 加密 + ///[src] 待加密字符串 + static Future encode(String src) async { + String publicKeyString = await rootBundle.loadString('keys/public_key.pem'); + RSAPublicKey publicKey = parser.parse(publicKeyString); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + return encrypter.encrypt(src).base64; + } + + /// 解密 + /// [decoded] 待解密字符串 + static Future decode(String decoded) async { + String privateKeyString = + await rootBundle.loadString('keys/private_key.pem'); + + final privateKey = parser.parse(privateKeyString); + + final encrypter = Encrypter(RSA(privateKey: privateKey)); + return encrypter.decrypt(Encrypted.fromBase64(decoded)); + } +} diff --git a/lib/utils/http_utils.dart b/lib/utils/http_utils.dart new file mode 100644 index 0000000..319ca63 --- /dev/null +++ b/lib/utils/http_utils.dart @@ -0,0 +1,30 @@ +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/models/common/version_model.dart'; + +/// 模拟网络请求数据 +class HttpUtils { + Future getSplash() { + return Future.delayed(Duration(milliseconds: 500), () { + return SplashModel( + title: 'Flutter 常用工具类库', + content: 'Flutter 常用工具类库', + url: 'https://www.jianshu.com/p/425a7ff9d66e', + imgUrl: + 'https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_common_utils_a.png', + ); + }); + } + + /// 该地址可能无法下载,请自行更换可测试apk地址。 + Future getVersion() async { + return Future.delayed(Duration(milliseconds: 500), () { + return VersionModel( + title: '有新版本v1.1.0,快去更新吧!', + content: '1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~', + url: + 'https://raw.githubusercontent.com/Sky24n/Doc/master/apks/flutter_wanandroid.apk', + version: '1.0.0', + ); + }); + } +} diff --git a/lib/utils/login_utils.dart b/lib/utils/login_utils.dart new file mode 100644 index 0000000..af31546 --- /dev/null +++ b/lib/utils/login_utils.dart @@ -0,0 +1,47 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flustars/flustars.dart'; + +/// 登录工具类 +class LoginUtils { + /// 判断用户是否已登录 + static Future isLogin() async { + // 1. 先判断token是否在 + bool hasToken = + ObjectUtil.isNotEmpty(SpUtil.getString(BaseConstant.keyAppToken)); + if (hasToken) { + // 2.用token去获取用户信息,有信息认为已登录,否则为未登录 + UserRepository userRepository = new UserRepository(); + UserModel user = await userRepository.getUserInfo(); + if (user == null) { + // 未登录的尝试自动登录,返回自动登录结果 + return await autoLogin(); + } else { + return true; + } + } else { + return hasToken; + } + } + + // 自动登录 + static Future autoLogin() async { + // 取用户名和密码自动登录 + String username = SpUtil.getString(BaseConstant.keyAccount); + String password = SpUtil.getString(BaseConstant.keyPassword); + UserRepository userRepository = new UserRepository(); + LoginReq req = new LoginReq(username, password); + try { + UserModel model = await userRepository.login(req); + if (model != null) { + return true; + } else { + return false; + } + } catch (error) { + return false; + } + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/route/fadeRoute.dart b/lib/ui/widgets/common/route/fadeRoute.dart new file mode 100644 index 0000000..09cda1e --- /dev/null +++ b/lib/ui/widgets/common/route/fadeRoute.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; + +///FadeRoute是自定义的切换过度动画(渐隐渐现) +class FadeRoute extends PageRouteBuilder { + final Widget page; + FadeRoute({this.page}): super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) =>page,transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) =>FadeTransition( + opacity: animation, + child: child, + ), + ); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/route/popRoute.dart b/lib/ui/widgets/common/route/popRoute.dart new file mode 100644 index 0000000..e779cd1 --- /dev/null +++ b/lib/ui/widgets/common/route/popRoute.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class PopRoute extends PopupRoute{ + final Duration _duration = Duration(milliseconds: 300); + Widget child; + + PopRoute({@required this.child}); + + @override + Color get barrierColor => null; + + @override + bool get barrierDismissible => true; + + @override + String get barrierLabel => null; + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + return child; + } + + @override + Duration get transitionDuration => _duration; + +} \ No newline at end of file diff --git a/lib/ui/widgets/common/web_scaffold.dart b/lib/ui/widgets/common/web_scaffold.dart new file mode 100644 index 0000000..3c7efe2 --- /dev/null +++ b/lib/ui/widgets/common/web_scaffold.dart @@ -0,0 +1,173 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; +import 'package:share/share.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +import 'button/likebtn/like_button.dart'; + +class WebScaffold extends StatefulWidget { + const WebScaffold({ + Key key, + this.title, + this.titleId, + this.url, + }) : super(key: key); + + final String title; + final String titleId; + final String url; + + @override + State createState() { + return new WebScaffoldState(); + } +} + +class WebScaffoldState extends State { +// WebViewController _webViewController; +// bool _isShowFloatBtn = false; + + void _onPopSelected(String value) { + String _title = widget.title ?? IntlUtil.getString(context, widget.titleId); + switch (value) { + case "browser": // 浏览 + NavigatorUtil.launchInBrowser(widget.url, title: _title); + break; + case "collection": // 收藏 + break; + case "share": // 分享 + String _url = widget.url; + Share.share('$_title : $_url'); + break; + default: + break; + } + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + centerTitle: true, + actions: [ + LikeButton( + width: 56.0, + duration: Duration(milliseconds: 500), + ), +// new IconButton(icon: new Icon(Icons.more_vert), onPressed: () {}), + new PopupMenuButton( + padding: const EdgeInsets.all(0.0), + onSelected: _onPopSelected, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: "browser", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '浏览器打开', + style: TextStyles.listContent, + ) + ], + ), + ))), +// new PopupMenuItem( +// value: "collection", +// child: ListTile( +// contentPadding: EdgeInsets.all(0.0), +// dense: false, +// title: new Container( +// alignment: Alignment.center, +// child: new Row( +// children: [ +// Icon( +// Icons.collections, +// color: Colours.gray_66, +// size: 22.0, +// ), +// Gaps.hGap10, +// Text( +// '收藏', +// style: TextStyles.listContent, +// ) +// ], +// ), +// ))), + new PopupMenuItem( + value: "share", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.share, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '分享', + style: TextStyles.listContent, + ) + ], + ), + ))), + ]) + ], + ), + body: new WebView( + onWebViewCreated: (WebViewController webViewController) { +// _webViewController = webViewController; +// _webViewController.addListener(() { +// int _scrollY = _webViewController.scrollY.toInt(); +// if (_scrollY < 480 && _isShowFloatBtn) { +// _isShowFloatBtn = false; +// setState(() {}); +// } else if (_scrollY > 480 && !_isShowFloatBtn) { +// _isShowFloatBtn = true; +// setState(() {}); +// } +// }); + }, + initialUrl: widget.url, + javascriptMode: JavascriptMode.unrestricted, + ), +// floatingActionButton: _buildFloatingActionButton(), + ); + } + +// Widget _buildFloatingActionButton() { +// if (_webViewController == null || _webViewController.scrollY < 480) { +// return null; +// } +// return new FloatingActionButton( +// heroTag: widget.title ?? widget.titleId, +// backgroundColor: Theme.of(context).primaryColor, +// child: Icon( +// Icons.keyboard_arrow_up, +// ), +// onPressed: () { +// _webViewController.scrollTop(); +// }); +// } +} diff --git a/lib/ui/widgets/login_page/login_item_widget.dart b/lib/ui/widgets/login_page/login_item_widget.dart new file mode 100644 index 0000000..58a8778 --- /dev/null +++ b/lib/ui/widgets/login_page/login_item_widget.dart @@ -0,0 +1,96 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 登录项 +class LoginItem extends StatefulWidget { + final IconData prefixIcon; // 前方icon + final bool hasSuffixIcon; // 是否要后面的icon + final String hintText; // 提示文字 + final bool autoFocus; // 自动聚焦 + final TextInputType keyboardType; // 键盘类型 + final int maxLength; // 最大程度 + final bool maxLengthEnforced; // 当长度达到限制长度时,是否强制组织输入 + final TextInputAction textInputAction; // 输入action + final TextEditingController controller; // controller + final FocusNode focusNode; //focusNode + final VoidCallback onEditingComplete; // 输入完毕后的回调 + + const LoginItem( + {Key key, + this.prefixIcon, + this.hasSuffixIcon = false, + this.autoFocus = false, + this.keyboardType = TextInputType.text, + this.hintText, + this.maxLength, + this.maxLengthEnforced = true, + this.textInputAction, + this.controller, + this.focusNode, + this.onEditingComplete}) + : super(key: key); + + @override + State createState() { + return LoginItemState(); + } +} + +class LoginItemState extends State { + bool _obscureText; // 是否隐藏原始文字 // 密码用 + + @override + void initState() { + super.initState(); + _obscureText = widget.hasSuffixIcon; + } + + @override + Widget build(BuildContext context) { + return new Row( + children: [ + new IconButton( + iconSize: 28, + icon: new Icon( + widget.prefixIcon, + color: Theme.of(context).primaryColor, + ), + onPressed: () {}), + Gaps.hGap5, + new Expanded( + child: new TextField( + textInputAction: widget.textInputAction, + focusNode: widget.focusNode, + onEditingComplete: widget.onEditingComplete, + obscureText: _obscureText, + controller: widget.controller, + maxLength: widget.maxLength, + maxLengthEnforced: widget.maxLengthEnforced, + style: new TextStyle(color: Colours.gray_66, fontSize: 14), + decoration: new InputDecoration( + hintText: widget.hintText, + hintStyle: new TextStyle(color: Colours.gray_99, fontSize: 14), + suffixIcon: widget.hasSuffixIcon + ? new IconButton( + icon: new Icon( + _obscureText + ? Icons.visibility + : Icons.visibility_off, + color: Colours.gray_66, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }) + : null, + focusedBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + enabledBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + )), + ), + ], + ); + } +} diff --git a/lib/utils/encrypt_helper.dart b/lib/utils/encrypt_helper.dart new file mode 100644 index 0000000..caf7196 --- /dev/null +++ b/lib/utils/encrypt_helper.dart @@ -0,0 +1,30 @@ +import 'package:encrypt/encrypt.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +import 'dart:async'; +import 'package:flutter/services.dart' show rootBundle; + +/// RSA加密工具 +final parser = RSAKeyParser(); + +class EncryptHelper { + /// 加密 + ///[src] 待加密字符串 + static Future encode(String src) async { + String publicKeyString = await rootBundle.loadString('keys/public_key.pem'); + RSAPublicKey publicKey = parser.parse(publicKeyString); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + return encrypter.encrypt(src).base64; + } + + /// 解密 + /// [decoded] 待解密字符串 + static Future decode(String decoded) async { + String privateKeyString = + await rootBundle.loadString('keys/private_key.pem'); + + final privateKey = parser.parse(privateKeyString); + + final encrypter = Encrypter(RSA(privateKey: privateKey)); + return encrypter.decrypt(Encrypted.fromBase64(decoded)); + } +} diff --git a/lib/utils/http_utils.dart b/lib/utils/http_utils.dart new file mode 100644 index 0000000..319ca63 --- /dev/null +++ b/lib/utils/http_utils.dart @@ -0,0 +1,30 @@ +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/models/common/version_model.dart'; + +/// 模拟网络请求数据 +class HttpUtils { + Future getSplash() { + return Future.delayed(Duration(milliseconds: 500), () { + return SplashModel( + title: 'Flutter 常用工具类库', + content: 'Flutter 常用工具类库', + url: 'https://www.jianshu.com/p/425a7ff9d66e', + imgUrl: + 'https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_common_utils_a.png', + ); + }); + } + + /// 该地址可能无法下载,请自行更换可测试apk地址。 + Future getVersion() async { + return Future.delayed(Duration(milliseconds: 500), () { + return VersionModel( + title: '有新版本v1.1.0,快去更新吧!', + content: '1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~', + url: + 'https://raw.githubusercontent.com/Sky24n/Doc/master/apks/flutter_wanandroid.apk', + version: '1.0.0', + ); + }); + } +} diff --git a/lib/utils/login_utils.dart b/lib/utils/login_utils.dart new file mode 100644 index 0000000..af31546 --- /dev/null +++ b/lib/utils/login_utils.dart @@ -0,0 +1,47 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flustars/flustars.dart'; + +/// 登录工具类 +class LoginUtils { + /// 判断用户是否已登录 + static Future isLogin() async { + // 1. 先判断token是否在 + bool hasToken = + ObjectUtil.isNotEmpty(SpUtil.getString(BaseConstant.keyAppToken)); + if (hasToken) { + // 2.用token去获取用户信息,有信息认为已登录,否则为未登录 + UserRepository userRepository = new UserRepository(); + UserModel user = await userRepository.getUserInfo(); + if (user == null) { + // 未登录的尝试自动登录,返回自动登录结果 + return await autoLogin(); + } else { + return true; + } + } else { + return hasToken; + } + } + + // 自动登录 + static Future autoLogin() async { + // 取用户名和密码自动登录 + String username = SpUtil.getString(BaseConstant.keyAccount); + String password = SpUtil.getString(BaseConstant.keyPassword); + UserRepository userRepository = new UserRepository(); + LoginReq req = new LoginReq(username, password); + try { + UserModel model = await userRepository.login(req); + if (model != null) { + return true; + } else { + return false; + } + } catch (error) { + return false; + } + } +} diff --git a/lib/utils/map_utils.dart b/lib/utils/map_utils.dart new file mode 100644 index 0000000..dc6029d --- /dev/null +++ b/lib/utils/map_utils.dart @@ -0,0 +1,72 @@ +import 'dart:math'; + +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; + +/// 地图工具类 +class MapUtils { + ///计算两点距离 + ///[start] 第一个点坐标[lng,lat] + ///[end]第二个点坐标[lng,lat] + static double calculateDistance(start, end) { + if ((start != null) || (end != null)) { + double d1 = 0.01745329251994329; + double d2 = start[0]; //lng + double d3 = start[1]; //lat + double d4 = end[0]; //lng + double d5 = end[1]; //lat + d2 *= d1; + d3 *= d1; + d4 *= d1; + d5 *= d1; + double d6 = sin(d2); + double d7 = sin(d3); + double d8 = cos(d2); + double d9 = cos(d3); + double d10 = sin(d4); + double d11 = sin(d5); + double d12 = cos(d4); + double d13 = cos(d5); + List arrayOfDouble1 = List(3); + List arrayOfDouble2 = List(3); + arrayOfDouble1[0] = (d9 * d8); + arrayOfDouble1[1] = (d9 * d6); + arrayOfDouble1[2] = d7; + arrayOfDouble2[0] = (d13 * d12); + arrayOfDouble2[1] = (d13 * d10); + arrayOfDouble2[2] = d11; + double d14 = sqrt((arrayOfDouble1[0] - arrayOfDouble2[0]) * + (arrayOfDouble1[0] - arrayOfDouble2[0]) + + (arrayOfDouble1[1] - arrayOfDouble2[1]) * + (arrayOfDouble1[1] - arrayOfDouble2[1]) + + (arrayOfDouble1[2] - arrayOfDouble2[2]) * + (arrayOfDouble1[2] - arrayOfDouble2[2])); + print((asin(d14 / 2.0) * 12742001.579854401)); + return (asin(d14 / 2.0) * 12742001.579854401).abs(); + } else { + return 0.0; + } + } +} + +/// 获取随机坐标 +mixin NextLatLng { + final random = Random(); + + LatLng getNextLatLng({LatLng center}) { + center ??= LatLng(39.90960, 116.397228); + return LatLng( + center.latitude + random.nextDouble(), + center.longitude + random.nextDouble(), + ); + } + + List getNextBatchLatLng(int count) { + return [ + for (int i = 0; i < count; i++) + LatLng( + 39.90960 + random.nextDouble() * 4, + 116.397228 + random.nextDouble() * 4, + ) + ]; + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/route/fadeRoute.dart b/lib/ui/widgets/common/route/fadeRoute.dart new file mode 100644 index 0000000..09cda1e --- /dev/null +++ b/lib/ui/widgets/common/route/fadeRoute.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; + +///FadeRoute是自定义的切换过度动画(渐隐渐现) +class FadeRoute extends PageRouteBuilder { + final Widget page; + FadeRoute({this.page}): super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) =>page,transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) =>FadeTransition( + opacity: animation, + child: child, + ), + ); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/route/popRoute.dart b/lib/ui/widgets/common/route/popRoute.dart new file mode 100644 index 0000000..e779cd1 --- /dev/null +++ b/lib/ui/widgets/common/route/popRoute.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class PopRoute extends PopupRoute{ + final Duration _duration = Duration(milliseconds: 300); + Widget child; + + PopRoute({@required this.child}); + + @override + Color get barrierColor => null; + + @override + bool get barrierDismissible => true; + + @override + String get barrierLabel => null; + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + return child; + } + + @override + Duration get transitionDuration => _duration; + +} \ No newline at end of file diff --git a/lib/ui/widgets/common/web_scaffold.dart b/lib/ui/widgets/common/web_scaffold.dart new file mode 100644 index 0000000..3c7efe2 --- /dev/null +++ b/lib/ui/widgets/common/web_scaffold.dart @@ -0,0 +1,173 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; +import 'package:share/share.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +import 'button/likebtn/like_button.dart'; + +class WebScaffold extends StatefulWidget { + const WebScaffold({ + Key key, + this.title, + this.titleId, + this.url, + }) : super(key: key); + + final String title; + final String titleId; + final String url; + + @override + State createState() { + return new WebScaffoldState(); + } +} + +class WebScaffoldState extends State { +// WebViewController _webViewController; +// bool _isShowFloatBtn = false; + + void _onPopSelected(String value) { + String _title = widget.title ?? IntlUtil.getString(context, widget.titleId); + switch (value) { + case "browser": // 浏览 + NavigatorUtil.launchInBrowser(widget.url, title: _title); + break; + case "collection": // 收藏 + break; + case "share": // 分享 + String _url = widget.url; + Share.share('$_title : $_url'); + break; + default: + break; + } + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + centerTitle: true, + actions: [ + LikeButton( + width: 56.0, + duration: Duration(milliseconds: 500), + ), +// new IconButton(icon: new Icon(Icons.more_vert), onPressed: () {}), + new PopupMenuButton( + padding: const EdgeInsets.all(0.0), + onSelected: _onPopSelected, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: "browser", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '浏览器打开', + style: TextStyles.listContent, + ) + ], + ), + ))), +// new PopupMenuItem( +// value: "collection", +// child: ListTile( +// contentPadding: EdgeInsets.all(0.0), +// dense: false, +// title: new Container( +// alignment: Alignment.center, +// child: new Row( +// children: [ +// Icon( +// Icons.collections, +// color: Colours.gray_66, +// size: 22.0, +// ), +// Gaps.hGap10, +// Text( +// '收藏', +// style: TextStyles.listContent, +// ) +// ], +// ), +// ))), + new PopupMenuItem( + value: "share", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.share, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '分享', + style: TextStyles.listContent, + ) + ], + ), + ))), + ]) + ], + ), + body: new WebView( + onWebViewCreated: (WebViewController webViewController) { +// _webViewController = webViewController; +// _webViewController.addListener(() { +// int _scrollY = _webViewController.scrollY.toInt(); +// if (_scrollY < 480 && _isShowFloatBtn) { +// _isShowFloatBtn = false; +// setState(() {}); +// } else if (_scrollY > 480 && !_isShowFloatBtn) { +// _isShowFloatBtn = true; +// setState(() {}); +// } +// }); + }, + initialUrl: widget.url, + javascriptMode: JavascriptMode.unrestricted, + ), +// floatingActionButton: _buildFloatingActionButton(), + ); + } + +// Widget _buildFloatingActionButton() { +// if (_webViewController == null || _webViewController.scrollY < 480) { +// return null; +// } +// return new FloatingActionButton( +// heroTag: widget.title ?? widget.titleId, +// backgroundColor: Theme.of(context).primaryColor, +// child: Icon( +// Icons.keyboard_arrow_up, +// ), +// onPressed: () { +// _webViewController.scrollTop(); +// }); +// } +} diff --git a/lib/ui/widgets/login_page/login_item_widget.dart b/lib/ui/widgets/login_page/login_item_widget.dart new file mode 100644 index 0000000..58a8778 --- /dev/null +++ b/lib/ui/widgets/login_page/login_item_widget.dart @@ -0,0 +1,96 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 登录项 +class LoginItem extends StatefulWidget { + final IconData prefixIcon; // 前方icon + final bool hasSuffixIcon; // 是否要后面的icon + final String hintText; // 提示文字 + final bool autoFocus; // 自动聚焦 + final TextInputType keyboardType; // 键盘类型 + final int maxLength; // 最大程度 + final bool maxLengthEnforced; // 当长度达到限制长度时,是否强制组织输入 + final TextInputAction textInputAction; // 输入action + final TextEditingController controller; // controller + final FocusNode focusNode; //focusNode + final VoidCallback onEditingComplete; // 输入完毕后的回调 + + const LoginItem( + {Key key, + this.prefixIcon, + this.hasSuffixIcon = false, + this.autoFocus = false, + this.keyboardType = TextInputType.text, + this.hintText, + this.maxLength, + this.maxLengthEnforced = true, + this.textInputAction, + this.controller, + this.focusNode, + this.onEditingComplete}) + : super(key: key); + + @override + State createState() { + return LoginItemState(); + } +} + +class LoginItemState extends State { + bool _obscureText; // 是否隐藏原始文字 // 密码用 + + @override + void initState() { + super.initState(); + _obscureText = widget.hasSuffixIcon; + } + + @override + Widget build(BuildContext context) { + return new Row( + children: [ + new IconButton( + iconSize: 28, + icon: new Icon( + widget.prefixIcon, + color: Theme.of(context).primaryColor, + ), + onPressed: () {}), + Gaps.hGap5, + new Expanded( + child: new TextField( + textInputAction: widget.textInputAction, + focusNode: widget.focusNode, + onEditingComplete: widget.onEditingComplete, + obscureText: _obscureText, + controller: widget.controller, + maxLength: widget.maxLength, + maxLengthEnforced: widget.maxLengthEnforced, + style: new TextStyle(color: Colours.gray_66, fontSize: 14), + decoration: new InputDecoration( + hintText: widget.hintText, + hintStyle: new TextStyle(color: Colours.gray_99, fontSize: 14), + suffixIcon: widget.hasSuffixIcon + ? new IconButton( + icon: new Icon( + _obscureText + ? Icons.visibility + : Icons.visibility_off, + color: Colours.gray_66, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }) + : null, + focusedBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + enabledBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + )), + ), + ], + ); + } +} diff --git a/lib/utils/encrypt_helper.dart b/lib/utils/encrypt_helper.dart new file mode 100644 index 0000000..caf7196 --- /dev/null +++ b/lib/utils/encrypt_helper.dart @@ -0,0 +1,30 @@ +import 'package:encrypt/encrypt.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +import 'dart:async'; +import 'package:flutter/services.dart' show rootBundle; + +/// RSA加密工具 +final parser = RSAKeyParser(); + +class EncryptHelper { + /// 加密 + ///[src] 待加密字符串 + static Future encode(String src) async { + String publicKeyString = await rootBundle.loadString('keys/public_key.pem'); + RSAPublicKey publicKey = parser.parse(publicKeyString); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + return encrypter.encrypt(src).base64; + } + + /// 解密 + /// [decoded] 待解密字符串 + static Future decode(String decoded) async { + String privateKeyString = + await rootBundle.loadString('keys/private_key.pem'); + + final privateKey = parser.parse(privateKeyString); + + final encrypter = Encrypter(RSA(privateKey: privateKey)); + return encrypter.decrypt(Encrypted.fromBase64(decoded)); + } +} diff --git a/lib/utils/http_utils.dart b/lib/utils/http_utils.dart new file mode 100644 index 0000000..319ca63 --- /dev/null +++ b/lib/utils/http_utils.dart @@ -0,0 +1,30 @@ +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/models/common/version_model.dart'; + +/// 模拟网络请求数据 +class HttpUtils { + Future getSplash() { + return Future.delayed(Duration(milliseconds: 500), () { + return SplashModel( + title: 'Flutter 常用工具类库', + content: 'Flutter 常用工具类库', + url: 'https://www.jianshu.com/p/425a7ff9d66e', + imgUrl: + 'https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_common_utils_a.png', + ); + }); + } + + /// 该地址可能无法下载,请自行更换可测试apk地址。 + Future getVersion() async { + return Future.delayed(Duration(milliseconds: 500), () { + return VersionModel( + title: '有新版本v1.1.0,快去更新吧!', + content: '1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~', + url: + 'https://raw.githubusercontent.com/Sky24n/Doc/master/apks/flutter_wanandroid.apk', + version: '1.0.0', + ); + }); + } +} diff --git a/lib/utils/login_utils.dart b/lib/utils/login_utils.dart new file mode 100644 index 0000000..af31546 --- /dev/null +++ b/lib/utils/login_utils.dart @@ -0,0 +1,47 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flustars/flustars.dart'; + +/// 登录工具类 +class LoginUtils { + /// 判断用户是否已登录 + static Future isLogin() async { + // 1. 先判断token是否在 + bool hasToken = + ObjectUtil.isNotEmpty(SpUtil.getString(BaseConstant.keyAppToken)); + if (hasToken) { + // 2.用token去获取用户信息,有信息认为已登录,否则为未登录 + UserRepository userRepository = new UserRepository(); + UserModel user = await userRepository.getUserInfo(); + if (user == null) { + // 未登录的尝试自动登录,返回自动登录结果 + return await autoLogin(); + } else { + return true; + } + } else { + return hasToken; + } + } + + // 自动登录 + static Future autoLogin() async { + // 取用户名和密码自动登录 + String username = SpUtil.getString(BaseConstant.keyAccount); + String password = SpUtil.getString(BaseConstant.keyPassword); + UserRepository userRepository = new UserRepository(); + LoginReq req = new LoginReq(username, password); + try { + UserModel model = await userRepository.login(req); + if (model != null) { + return true; + } else { + return false; + } + } catch (error) { + return false; + } + } +} diff --git a/lib/utils/map_utils.dart b/lib/utils/map_utils.dart new file mode 100644 index 0000000..dc6029d --- /dev/null +++ b/lib/utils/map_utils.dart @@ -0,0 +1,72 @@ +import 'dart:math'; + +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; + +/// 地图工具类 +class MapUtils { + ///计算两点距离 + ///[start] 第一个点坐标[lng,lat] + ///[end]第二个点坐标[lng,lat] + static double calculateDistance(start, end) { + if ((start != null) || (end != null)) { + double d1 = 0.01745329251994329; + double d2 = start[0]; //lng + double d3 = start[1]; //lat + double d4 = end[0]; //lng + double d5 = end[1]; //lat + d2 *= d1; + d3 *= d1; + d4 *= d1; + d5 *= d1; + double d6 = sin(d2); + double d7 = sin(d3); + double d8 = cos(d2); + double d9 = cos(d3); + double d10 = sin(d4); + double d11 = sin(d5); + double d12 = cos(d4); + double d13 = cos(d5); + List arrayOfDouble1 = List(3); + List arrayOfDouble2 = List(3); + arrayOfDouble1[0] = (d9 * d8); + arrayOfDouble1[1] = (d9 * d6); + arrayOfDouble1[2] = d7; + arrayOfDouble2[0] = (d13 * d12); + arrayOfDouble2[1] = (d13 * d10); + arrayOfDouble2[2] = d11; + double d14 = sqrt((arrayOfDouble1[0] - arrayOfDouble2[0]) * + (arrayOfDouble1[0] - arrayOfDouble2[0]) + + (arrayOfDouble1[1] - arrayOfDouble2[1]) * + (arrayOfDouble1[1] - arrayOfDouble2[1]) + + (arrayOfDouble1[2] - arrayOfDouble2[2]) * + (arrayOfDouble1[2] - arrayOfDouble2[2])); + print((asin(d14 / 2.0) * 12742001.579854401)); + return (asin(d14 / 2.0) * 12742001.579854401).abs(); + } else { + return 0.0; + } + } +} + +/// 获取随机坐标 +mixin NextLatLng { + final random = Random(); + + LatLng getNextLatLng({LatLng center}) { + center ??= LatLng(39.90960, 116.397228); + return LatLng( + center.latitude + random.nextDouble(), + center.longitude + random.nextDouble(), + ); + } + + List getNextBatchLatLng(int count) { + return [ + for (int i = 0; i < count; i++) + LatLng( + 39.90960 + random.nextDouble() * 4, + 116.397228 + random.nextDouble() * 4, + ) + ]; + } +} diff --git a/lib/utils/navigator_util.dart b/lib/utils/navigator_util.dart new file mode 100644 index 0000000..00c6bc1 --- /dev/null +++ b/lib/utils/navigator_util.dart @@ -0,0 +1,52 @@ +import 'package:base_app/ui/pages/user/user_login_page.dart'; +import 'package:base_app/ui/widgets/common/web_scaffold.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class NavigatorUtil { + // 打开页面 + static void pushPage( + BuildContext context, + Widget page, { + String pageName, + bool needLogin = false, + }) async { + if (context == null || page == null) return; + bool isLogin = await LoginUtils.isLogin(); + if (needLogin && isLogin == false) { + pushPage(context, UserLoginPage()); + return; + } + Navigator.push( + context, new CupertinoPageRoute(builder: (ctx) => page)); + } + + // 打开网页 + static void pushWeb(BuildContext context, + {String title, String titleId, String url}) { + if (context == null || ObjectUtil.isEmpty(url)) return; + if (url.endsWith(".apk")) { + launchInBrowser(url, title: title ?? titleId); + } else { + Navigator.push( + context, + new CupertinoPageRoute( + builder: (ctx) => new WebScaffold( + title: title, + titleId: titleId, + url: url, + ))); + } + } + + // 打开浏览器 + static Future launchInBrowser(String url, {String title}) async { + if (await canLaunch(url)) { + await launch(url, forceSafariVC: false, forceWebView: false); + } else { + throw 'Could not launch $url'; + } + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/route/fadeRoute.dart b/lib/ui/widgets/common/route/fadeRoute.dart new file mode 100644 index 0000000..09cda1e --- /dev/null +++ b/lib/ui/widgets/common/route/fadeRoute.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; + +///FadeRoute是自定义的切换过度动画(渐隐渐现) +class FadeRoute extends PageRouteBuilder { + final Widget page; + FadeRoute({this.page}): super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) =>page,transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) =>FadeTransition( + opacity: animation, + child: child, + ), + ); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/route/popRoute.dart b/lib/ui/widgets/common/route/popRoute.dart new file mode 100644 index 0000000..e779cd1 --- /dev/null +++ b/lib/ui/widgets/common/route/popRoute.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class PopRoute extends PopupRoute{ + final Duration _duration = Duration(milliseconds: 300); + Widget child; + + PopRoute({@required this.child}); + + @override + Color get barrierColor => null; + + @override + bool get barrierDismissible => true; + + @override + String get barrierLabel => null; + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + return child; + } + + @override + Duration get transitionDuration => _duration; + +} \ No newline at end of file diff --git a/lib/ui/widgets/common/web_scaffold.dart b/lib/ui/widgets/common/web_scaffold.dart new file mode 100644 index 0000000..3c7efe2 --- /dev/null +++ b/lib/ui/widgets/common/web_scaffold.dart @@ -0,0 +1,173 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; +import 'package:share/share.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +import 'button/likebtn/like_button.dart'; + +class WebScaffold extends StatefulWidget { + const WebScaffold({ + Key key, + this.title, + this.titleId, + this.url, + }) : super(key: key); + + final String title; + final String titleId; + final String url; + + @override + State createState() { + return new WebScaffoldState(); + } +} + +class WebScaffoldState extends State { +// WebViewController _webViewController; +// bool _isShowFloatBtn = false; + + void _onPopSelected(String value) { + String _title = widget.title ?? IntlUtil.getString(context, widget.titleId); + switch (value) { + case "browser": // 浏览 + NavigatorUtil.launchInBrowser(widget.url, title: _title); + break; + case "collection": // 收藏 + break; + case "share": // 分享 + String _url = widget.url; + Share.share('$_title : $_url'); + break; + default: + break; + } + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + centerTitle: true, + actions: [ + LikeButton( + width: 56.0, + duration: Duration(milliseconds: 500), + ), +// new IconButton(icon: new Icon(Icons.more_vert), onPressed: () {}), + new PopupMenuButton( + padding: const EdgeInsets.all(0.0), + onSelected: _onPopSelected, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: "browser", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '浏览器打开', + style: TextStyles.listContent, + ) + ], + ), + ))), +// new PopupMenuItem( +// value: "collection", +// child: ListTile( +// contentPadding: EdgeInsets.all(0.0), +// dense: false, +// title: new Container( +// alignment: Alignment.center, +// child: new Row( +// children: [ +// Icon( +// Icons.collections, +// color: Colours.gray_66, +// size: 22.0, +// ), +// Gaps.hGap10, +// Text( +// '收藏', +// style: TextStyles.listContent, +// ) +// ], +// ), +// ))), + new PopupMenuItem( + value: "share", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.share, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '分享', + style: TextStyles.listContent, + ) + ], + ), + ))), + ]) + ], + ), + body: new WebView( + onWebViewCreated: (WebViewController webViewController) { +// _webViewController = webViewController; +// _webViewController.addListener(() { +// int _scrollY = _webViewController.scrollY.toInt(); +// if (_scrollY < 480 && _isShowFloatBtn) { +// _isShowFloatBtn = false; +// setState(() {}); +// } else if (_scrollY > 480 && !_isShowFloatBtn) { +// _isShowFloatBtn = true; +// setState(() {}); +// } +// }); + }, + initialUrl: widget.url, + javascriptMode: JavascriptMode.unrestricted, + ), +// floatingActionButton: _buildFloatingActionButton(), + ); + } + +// Widget _buildFloatingActionButton() { +// if (_webViewController == null || _webViewController.scrollY < 480) { +// return null; +// } +// return new FloatingActionButton( +// heroTag: widget.title ?? widget.titleId, +// backgroundColor: Theme.of(context).primaryColor, +// child: Icon( +// Icons.keyboard_arrow_up, +// ), +// onPressed: () { +// _webViewController.scrollTop(); +// }); +// } +} diff --git a/lib/ui/widgets/login_page/login_item_widget.dart b/lib/ui/widgets/login_page/login_item_widget.dart new file mode 100644 index 0000000..58a8778 --- /dev/null +++ b/lib/ui/widgets/login_page/login_item_widget.dart @@ -0,0 +1,96 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 登录项 +class LoginItem extends StatefulWidget { + final IconData prefixIcon; // 前方icon + final bool hasSuffixIcon; // 是否要后面的icon + final String hintText; // 提示文字 + final bool autoFocus; // 自动聚焦 + final TextInputType keyboardType; // 键盘类型 + final int maxLength; // 最大程度 + final bool maxLengthEnforced; // 当长度达到限制长度时,是否强制组织输入 + final TextInputAction textInputAction; // 输入action + final TextEditingController controller; // controller + final FocusNode focusNode; //focusNode + final VoidCallback onEditingComplete; // 输入完毕后的回调 + + const LoginItem( + {Key key, + this.prefixIcon, + this.hasSuffixIcon = false, + this.autoFocus = false, + this.keyboardType = TextInputType.text, + this.hintText, + this.maxLength, + this.maxLengthEnforced = true, + this.textInputAction, + this.controller, + this.focusNode, + this.onEditingComplete}) + : super(key: key); + + @override + State createState() { + return LoginItemState(); + } +} + +class LoginItemState extends State { + bool _obscureText; // 是否隐藏原始文字 // 密码用 + + @override + void initState() { + super.initState(); + _obscureText = widget.hasSuffixIcon; + } + + @override + Widget build(BuildContext context) { + return new Row( + children: [ + new IconButton( + iconSize: 28, + icon: new Icon( + widget.prefixIcon, + color: Theme.of(context).primaryColor, + ), + onPressed: () {}), + Gaps.hGap5, + new Expanded( + child: new TextField( + textInputAction: widget.textInputAction, + focusNode: widget.focusNode, + onEditingComplete: widget.onEditingComplete, + obscureText: _obscureText, + controller: widget.controller, + maxLength: widget.maxLength, + maxLengthEnforced: widget.maxLengthEnforced, + style: new TextStyle(color: Colours.gray_66, fontSize: 14), + decoration: new InputDecoration( + hintText: widget.hintText, + hintStyle: new TextStyle(color: Colours.gray_99, fontSize: 14), + suffixIcon: widget.hasSuffixIcon + ? new IconButton( + icon: new Icon( + _obscureText + ? Icons.visibility + : Icons.visibility_off, + color: Colours.gray_66, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }) + : null, + focusedBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + enabledBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + )), + ), + ], + ); + } +} diff --git a/lib/utils/encrypt_helper.dart b/lib/utils/encrypt_helper.dart new file mode 100644 index 0000000..caf7196 --- /dev/null +++ b/lib/utils/encrypt_helper.dart @@ -0,0 +1,30 @@ +import 'package:encrypt/encrypt.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +import 'dart:async'; +import 'package:flutter/services.dart' show rootBundle; + +/// RSA加密工具 +final parser = RSAKeyParser(); + +class EncryptHelper { + /// 加密 + ///[src] 待加密字符串 + static Future encode(String src) async { + String publicKeyString = await rootBundle.loadString('keys/public_key.pem'); + RSAPublicKey publicKey = parser.parse(publicKeyString); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + return encrypter.encrypt(src).base64; + } + + /// 解密 + /// [decoded] 待解密字符串 + static Future decode(String decoded) async { + String privateKeyString = + await rootBundle.loadString('keys/private_key.pem'); + + final privateKey = parser.parse(privateKeyString); + + final encrypter = Encrypter(RSA(privateKey: privateKey)); + return encrypter.decrypt(Encrypted.fromBase64(decoded)); + } +} diff --git a/lib/utils/http_utils.dart b/lib/utils/http_utils.dart new file mode 100644 index 0000000..319ca63 --- /dev/null +++ b/lib/utils/http_utils.dart @@ -0,0 +1,30 @@ +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/models/common/version_model.dart'; + +/// 模拟网络请求数据 +class HttpUtils { + Future getSplash() { + return Future.delayed(Duration(milliseconds: 500), () { + return SplashModel( + title: 'Flutter 常用工具类库', + content: 'Flutter 常用工具类库', + url: 'https://www.jianshu.com/p/425a7ff9d66e', + imgUrl: + 'https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_common_utils_a.png', + ); + }); + } + + /// 该地址可能无法下载,请自行更换可测试apk地址。 + Future getVersion() async { + return Future.delayed(Duration(milliseconds: 500), () { + return VersionModel( + title: '有新版本v1.1.0,快去更新吧!', + content: '1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~', + url: + 'https://raw.githubusercontent.com/Sky24n/Doc/master/apks/flutter_wanandroid.apk', + version: '1.0.0', + ); + }); + } +} diff --git a/lib/utils/login_utils.dart b/lib/utils/login_utils.dart new file mode 100644 index 0000000..af31546 --- /dev/null +++ b/lib/utils/login_utils.dart @@ -0,0 +1,47 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flustars/flustars.dart'; + +/// 登录工具类 +class LoginUtils { + /// 判断用户是否已登录 + static Future isLogin() async { + // 1. 先判断token是否在 + bool hasToken = + ObjectUtil.isNotEmpty(SpUtil.getString(BaseConstant.keyAppToken)); + if (hasToken) { + // 2.用token去获取用户信息,有信息认为已登录,否则为未登录 + UserRepository userRepository = new UserRepository(); + UserModel user = await userRepository.getUserInfo(); + if (user == null) { + // 未登录的尝试自动登录,返回自动登录结果 + return await autoLogin(); + } else { + return true; + } + } else { + return hasToken; + } + } + + // 自动登录 + static Future autoLogin() async { + // 取用户名和密码自动登录 + String username = SpUtil.getString(BaseConstant.keyAccount); + String password = SpUtil.getString(BaseConstant.keyPassword); + UserRepository userRepository = new UserRepository(); + LoginReq req = new LoginReq(username, password); + try { + UserModel model = await userRepository.login(req); + if (model != null) { + return true; + } else { + return false; + } + } catch (error) { + return false; + } + } +} diff --git a/lib/utils/map_utils.dart b/lib/utils/map_utils.dart new file mode 100644 index 0000000..dc6029d --- /dev/null +++ b/lib/utils/map_utils.dart @@ -0,0 +1,72 @@ +import 'dart:math'; + +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; + +/// 地图工具类 +class MapUtils { + ///计算两点距离 + ///[start] 第一个点坐标[lng,lat] + ///[end]第二个点坐标[lng,lat] + static double calculateDistance(start, end) { + if ((start != null) || (end != null)) { + double d1 = 0.01745329251994329; + double d2 = start[0]; //lng + double d3 = start[1]; //lat + double d4 = end[0]; //lng + double d5 = end[1]; //lat + d2 *= d1; + d3 *= d1; + d4 *= d1; + d5 *= d1; + double d6 = sin(d2); + double d7 = sin(d3); + double d8 = cos(d2); + double d9 = cos(d3); + double d10 = sin(d4); + double d11 = sin(d5); + double d12 = cos(d4); + double d13 = cos(d5); + List arrayOfDouble1 = List(3); + List arrayOfDouble2 = List(3); + arrayOfDouble1[0] = (d9 * d8); + arrayOfDouble1[1] = (d9 * d6); + arrayOfDouble1[2] = d7; + arrayOfDouble2[0] = (d13 * d12); + arrayOfDouble2[1] = (d13 * d10); + arrayOfDouble2[2] = d11; + double d14 = sqrt((arrayOfDouble1[0] - arrayOfDouble2[0]) * + (arrayOfDouble1[0] - arrayOfDouble2[0]) + + (arrayOfDouble1[1] - arrayOfDouble2[1]) * + (arrayOfDouble1[1] - arrayOfDouble2[1]) + + (arrayOfDouble1[2] - arrayOfDouble2[2]) * + (arrayOfDouble1[2] - arrayOfDouble2[2])); + print((asin(d14 / 2.0) * 12742001.579854401)); + return (asin(d14 / 2.0) * 12742001.579854401).abs(); + } else { + return 0.0; + } + } +} + +/// 获取随机坐标 +mixin NextLatLng { + final random = Random(); + + LatLng getNextLatLng({LatLng center}) { + center ??= LatLng(39.90960, 116.397228); + return LatLng( + center.latitude + random.nextDouble(), + center.longitude + random.nextDouble(), + ); + } + + List getNextBatchLatLng(int count) { + return [ + for (int i = 0; i < count; i++) + LatLng( + 39.90960 + random.nextDouble() * 4, + 116.397228 + random.nextDouble() * 4, + ) + ]; + } +} diff --git a/lib/utils/navigator_util.dart b/lib/utils/navigator_util.dart new file mode 100644 index 0000000..00c6bc1 --- /dev/null +++ b/lib/utils/navigator_util.dart @@ -0,0 +1,52 @@ +import 'package:base_app/ui/pages/user/user_login_page.dart'; +import 'package:base_app/ui/widgets/common/web_scaffold.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class NavigatorUtil { + // 打开页面 + static void pushPage( + BuildContext context, + Widget page, { + String pageName, + bool needLogin = false, + }) async { + if (context == null || page == null) return; + bool isLogin = await LoginUtils.isLogin(); + if (needLogin && isLogin == false) { + pushPage(context, UserLoginPage()); + return; + } + Navigator.push( + context, new CupertinoPageRoute(builder: (ctx) => page)); + } + + // 打开网页 + static void pushWeb(BuildContext context, + {String title, String titleId, String url}) { + if (context == null || ObjectUtil.isEmpty(url)) return; + if (url.endsWith(".apk")) { + launchInBrowser(url, title: title ?? titleId); + } else { + Navigator.push( + context, + new CupertinoPageRoute( + builder: (ctx) => new WebScaffold( + title: title, + titleId: titleId, + url: url, + ))); + } + } + + // 打开浏览器 + static Future launchInBrowser(String url, {String title}) async { + if (await canLaunch(url)) { + await launch(url, forceSafariVC: false, forceWebView: false); + } else { + throw 'Could not launch $url'; + } + } +} diff --git a/lib/utils/permission_util.dart b/lib/utils/permission_util.dart new file mode 100644 index 0000000..6e75801 --- /dev/null +++ b/lib/utils/permission_util.dart @@ -0,0 +1,15 @@ +import 'package:oktoast/oktoast.dart'; +import 'package:permission_handler/permission_handler.dart'; + +/// 请求权限工具 + +/// 请求位置权限 +Future reqPositionPermission() async { + final status = await Permission.location.request(); + if (status == PermissionStatus.granted) { + return true; + } else { + showToast('需要定位权限,请去设置中开启'); + return false; + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/route/fadeRoute.dart b/lib/ui/widgets/common/route/fadeRoute.dart new file mode 100644 index 0000000..09cda1e --- /dev/null +++ b/lib/ui/widgets/common/route/fadeRoute.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; + +///FadeRoute是自定义的切换过度动画(渐隐渐现) +class FadeRoute extends PageRouteBuilder { + final Widget page; + FadeRoute({this.page}): super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) =>page,transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) =>FadeTransition( + opacity: animation, + child: child, + ), + ); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/route/popRoute.dart b/lib/ui/widgets/common/route/popRoute.dart new file mode 100644 index 0000000..e779cd1 --- /dev/null +++ b/lib/ui/widgets/common/route/popRoute.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class PopRoute extends PopupRoute{ + final Duration _duration = Duration(milliseconds: 300); + Widget child; + + PopRoute({@required this.child}); + + @override + Color get barrierColor => null; + + @override + bool get barrierDismissible => true; + + @override + String get barrierLabel => null; + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + return child; + } + + @override + Duration get transitionDuration => _duration; + +} \ No newline at end of file diff --git a/lib/ui/widgets/common/web_scaffold.dart b/lib/ui/widgets/common/web_scaffold.dart new file mode 100644 index 0000000..3c7efe2 --- /dev/null +++ b/lib/ui/widgets/common/web_scaffold.dart @@ -0,0 +1,173 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; +import 'package:share/share.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +import 'button/likebtn/like_button.dart'; + +class WebScaffold extends StatefulWidget { + const WebScaffold({ + Key key, + this.title, + this.titleId, + this.url, + }) : super(key: key); + + final String title; + final String titleId; + final String url; + + @override + State createState() { + return new WebScaffoldState(); + } +} + +class WebScaffoldState extends State { +// WebViewController _webViewController; +// bool _isShowFloatBtn = false; + + void _onPopSelected(String value) { + String _title = widget.title ?? IntlUtil.getString(context, widget.titleId); + switch (value) { + case "browser": // 浏览 + NavigatorUtil.launchInBrowser(widget.url, title: _title); + break; + case "collection": // 收藏 + break; + case "share": // 分享 + String _url = widget.url; + Share.share('$_title : $_url'); + break; + default: + break; + } + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + centerTitle: true, + actions: [ + LikeButton( + width: 56.0, + duration: Duration(milliseconds: 500), + ), +// new IconButton(icon: new Icon(Icons.more_vert), onPressed: () {}), + new PopupMenuButton( + padding: const EdgeInsets.all(0.0), + onSelected: _onPopSelected, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: "browser", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '浏览器打开', + style: TextStyles.listContent, + ) + ], + ), + ))), +// new PopupMenuItem( +// value: "collection", +// child: ListTile( +// contentPadding: EdgeInsets.all(0.0), +// dense: false, +// title: new Container( +// alignment: Alignment.center, +// child: new Row( +// children: [ +// Icon( +// Icons.collections, +// color: Colours.gray_66, +// size: 22.0, +// ), +// Gaps.hGap10, +// Text( +// '收藏', +// style: TextStyles.listContent, +// ) +// ], +// ), +// ))), + new PopupMenuItem( + value: "share", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.share, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '分享', + style: TextStyles.listContent, + ) + ], + ), + ))), + ]) + ], + ), + body: new WebView( + onWebViewCreated: (WebViewController webViewController) { +// _webViewController = webViewController; +// _webViewController.addListener(() { +// int _scrollY = _webViewController.scrollY.toInt(); +// if (_scrollY < 480 && _isShowFloatBtn) { +// _isShowFloatBtn = false; +// setState(() {}); +// } else if (_scrollY > 480 && !_isShowFloatBtn) { +// _isShowFloatBtn = true; +// setState(() {}); +// } +// }); + }, + initialUrl: widget.url, + javascriptMode: JavascriptMode.unrestricted, + ), +// floatingActionButton: _buildFloatingActionButton(), + ); + } + +// Widget _buildFloatingActionButton() { +// if (_webViewController == null || _webViewController.scrollY < 480) { +// return null; +// } +// return new FloatingActionButton( +// heroTag: widget.title ?? widget.titleId, +// backgroundColor: Theme.of(context).primaryColor, +// child: Icon( +// Icons.keyboard_arrow_up, +// ), +// onPressed: () { +// _webViewController.scrollTop(); +// }); +// } +} diff --git a/lib/ui/widgets/login_page/login_item_widget.dart b/lib/ui/widgets/login_page/login_item_widget.dart new file mode 100644 index 0000000..58a8778 --- /dev/null +++ b/lib/ui/widgets/login_page/login_item_widget.dart @@ -0,0 +1,96 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 登录项 +class LoginItem extends StatefulWidget { + final IconData prefixIcon; // 前方icon + final bool hasSuffixIcon; // 是否要后面的icon + final String hintText; // 提示文字 + final bool autoFocus; // 自动聚焦 + final TextInputType keyboardType; // 键盘类型 + final int maxLength; // 最大程度 + final bool maxLengthEnforced; // 当长度达到限制长度时,是否强制组织输入 + final TextInputAction textInputAction; // 输入action + final TextEditingController controller; // controller + final FocusNode focusNode; //focusNode + final VoidCallback onEditingComplete; // 输入完毕后的回调 + + const LoginItem( + {Key key, + this.prefixIcon, + this.hasSuffixIcon = false, + this.autoFocus = false, + this.keyboardType = TextInputType.text, + this.hintText, + this.maxLength, + this.maxLengthEnforced = true, + this.textInputAction, + this.controller, + this.focusNode, + this.onEditingComplete}) + : super(key: key); + + @override + State createState() { + return LoginItemState(); + } +} + +class LoginItemState extends State { + bool _obscureText; // 是否隐藏原始文字 // 密码用 + + @override + void initState() { + super.initState(); + _obscureText = widget.hasSuffixIcon; + } + + @override + Widget build(BuildContext context) { + return new Row( + children: [ + new IconButton( + iconSize: 28, + icon: new Icon( + widget.prefixIcon, + color: Theme.of(context).primaryColor, + ), + onPressed: () {}), + Gaps.hGap5, + new Expanded( + child: new TextField( + textInputAction: widget.textInputAction, + focusNode: widget.focusNode, + onEditingComplete: widget.onEditingComplete, + obscureText: _obscureText, + controller: widget.controller, + maxLength: widget.maxLength, + maxLengthEnforced: widget.maxLengthEnforced, + style: new TextStyle(color: Colours.gray_66, fontSize: 14), + decoration: new InputDecoration( + hintText: widget.hintText, + hintStyle: new TextStyle(color: Colours.gray_99, fontSize: 14), + suffixIcon: widget.hasSuffixIcon + ? new IconButton( + icon: new Icon( + _obscureText + ? Icons.visibility + : Icons.visibility_off, + color: Colours.gray_66, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }) + : null, + focusedBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + enabledBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + )), + ), + ], + ); + } +} diff --git a/lib/utils/encrypt_helper.dart b/lib/utils/encrypt_helper.dart new file mode 100644 index 0000000..caf7196 --- /dev/null +++ b/lib/utils/encrypt_helper.dart @@ -0,0 +1,30 @@ +import 'package:encrypt/encrypt.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +import 'dart:async'; +import 'package:flutter/services.dart' show rootBundle; + +/// RSA加密工具 +final parser = RSAKeyParser(); + +class EncryptHelper { + /// 加密 + ///[src] 待加密字符串 + static Future encode(String src) async { + String publicKeyString = await rootBundle.loadString('keys/public_key.pem'); + RSAPublicKey publicKey = parser.parse(publicKeyString); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + return encrypter.encrypt(src).base64; + } + + /// 解密 + /// [decoded] 待解密字符串 + static Future decode(String decoded) async { + String privateKeyString = + await rootBundle.loadString('keys/private_key.pem'); + + final privateKey = parser.parse(privateKeyString); + + final encrypter = Encrypter(RSA(privateKey: privateKey)); + return encrypter.decrypt(Encrypted.fromBase64(decoded)); + } +} diff --git a/lib/utils/http_utils.dart b/lib/utils/http_utils.dart new file mode 100644 index 0000000..319ca63 --- /dev/null +++ b/lib/utils/http_utils.dart @@ -0,0 +1,30 @@ +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/models/common/version_model.dart'; + +/// 模拟网络请求数据 +class HttpUtils { + Future getSplash() { + return Future.delayed(Duration(milliseconds: 500), () { + return SplashModel( + title: 'Flutter 常用工具类库', + content: 'Flutter 常用工具类库', + url: 'https://www.jianshu.com/p/425a7ff9d66e', + imgUrl: + 'https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_common_utils_a.png', + ); + }); + } + + /// 该地址可能无法下载,请自行更换可测试apk地址。 + Future getVersion() async { + return Future.delayed(Duration(milliseconds: 500), () { + return VersionModel( + title: '有新版本v1.1.0,快去更新吧!', + content: '1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~', + url: + 'https://raw.githubusercontent.com/Sky24n/Doc/master/apks/flutter_wanandroid.apk', + version: '1.0.0', + ); + }); + } +} diff --git a/lib/utils/login_utils.dart b/lib/utils/login_utils.dart new file mode 100644 index 0000000..af31546 --- /dev/null +++ b/lib/utils/login_utils.dart @@ -0,0 +1,47 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flustars/flustars.dart'; + +/// 登录工具类 +class LoginUtils { + /// 判断用户是否已登录 + static Future isLogin() async { + // 1. 先判断token是否在 + bool hasToken = + ObjectUtil.isNotEmpty(SpUtil.getString(BaseConstant.keyAppToken)); + if (hasToken) { + // 2.用token去获取用户信息,有信息认为已登录,否则为未登录 + UserRepository userRepository = new UserRepository(); + UserModel user = await userRepository.getUserInfo(); + if (user == null) { + // 未登录的尝试自动登录,返回自动登录结果 + return await autoLogin(); + } else { + return true; + } + } else { + return hasToken; + } + } + + // 自动登录 + static Future autoLogin() async { + // 取用户名和密码自动登录 + String username = SpUtil.getString(BaseConstant.keyAccount); + String password = SpUtil.getString(BaseConstant.keyPassword); + UserRepository userRepository = new UserRepository(); + LoginReq req = new LoginReq(username, password); + try { + UserModel model = await userRepository.login(req); + if (model != null) { + return true; + } else { + return false; + } + } catch (error) { + return false; + } + } +} diff --git a/lib/utils/map_utils.dart b/lib/utils/map_utils.dart new file mode 100644 index 0000000..dc6029d --- /dev/null +++ b/lib/utils/map_utils.dart @@ -0,0 +1,72 @@ +import 'dart:math'; + +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; + +/// 地图工具类 +class MapUtils { + ///计算两点距离 + ///[start] 第一个点坐标[lng,lat] + ///[end]第二个点坐标[lng,lat] + static double calculateDistance(start, end) { + if ((start != null) || (end != null)) { + double d1 = 0.01745329251994329; + double d2 = start[0]; //lng + double d3 = start[1]; //lat + double d4 = end[0]; //lng + double d5 = end[1]; //lat + d2 *= d1; + d3 *= d1; + d4 *= d1; + d5 *= d1; + double d6 = sin(d2); + double d7 = sin(d3); + double d8 = cos(d2); + double d9 = cos(d3); + double d10 = sin(d4); + double d11 = sin(d5); + double d12 = cos(d4); + double d13 = cos(d5); + List arrayOfDouble1 = List(3); + List arrayOfDouble2 = List(3); + arrayOfDouble1[0] = (d9 * d8); + arrayOfDouble1[1] = (d9 * d6); + arrayOfDouble1[2] = d7; + arrayOfDouble2[0] = (d13 * d12); + arrayOfDouble2[1] = (d13 * d10); + arrayOfDouble2[2] = d11; + double d14 = sqrt((arrayOfDouble1[0] - arrayOfDouble2[0]) * + (arrayOfDouble1[0] - arrayOfDouble2[0]) + + (arrayOfDouble1[1] - arrayOfDouble2[1]) * + (arrayOfDouble1[1] - arrayOfDouble2[1]) + + (arrayOfDouble1[2] - arrayOfDouble2[2]) * + (arrayOfDouble1[2] - arrayOfDouble2[2])); + print((asin(d14 / 2.0) * 12742001.579854401)); + return (asin(d14 / 2.0) * 12742001.579854401).abs(); + } else { + return 0.0; + } + } +} + +/// 获取随机坐标 +mixin NextLatLng { + final random = Random(); + + LatLng getNextLatLng({LatLng center}) { + center ??= LatLng(39.90960, 116.397228); + return LatLng( + center.latitude + random.nextDouble(), + center.longitude + random.nextDouble(), + ); + } + + List getNextBatchLatLng(int count) { + return [ + for (int i = 0; i < count; i++) + LatLng( + 39.90960 + random.nextDouble() * 4, + 116.397228 + random.nextDouble() * 4, + ) + ]; + } +} diff --git a/lib/utils/navigator_util.dart b/lib/utils/navigator_util.dart new file mode 100644 index 0000000..00c6bc1 --- /dev/null +++ b/lib/utils/navigator_util.dart @@ -0,0 +1,52 @@ +import 'package:base_app/ui/pages/user/user_login_page.dart'; +import 'package:base_app/ui/widgets/common/web_scaffold.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class NavigatorUtil { + // 打开页面 + static void pushPage( + BuildContext context, + Widget page, { + String pageName, + bool needLogin = false, + }) async { + if (context == null || page == null) return; + bool isLogin = await LoginUtils.isLogin(); + if (needLogin && isLogin == false) { + pushPage(context, UserLoginPage()); + return; + } + Navigator.push( + context, new CupertinoPageRoute(builder: (ctx) => page)); + } + + // 打开网页 + static void pushWeb(BuildContext context, + {String title, String titleId, String url}) { + if (context == null || ObjectUtil.isEmpty(url)) return; + if (url.endsWith(".apk")) { + launchInBrowser(url, title: title ?? titleId); + } else { + Navigator.push( + context, + new CupertinoPageRoute( + builder: (ctx) => new WebScaffold( + title: title, + titleId: titleId, + url: url, + ))); + } + } + + // 打开浏览器 + static Future launchInBrowser(String url, {String title}) async { + if (await canLaunch(url)) { + await launch(url, forceSafariVC: false, forceWebView: false); + } else { + throw 'Could not launch $url'; + } + } +} diff --git a/lib/utils/permission_util.dart b/lib/utils/permission_util.dart new file mode 100644 index 0000000..6e75801 --- /dev/null +++ b/lib/utils/permission_util.dart @@ -0,0 +1,15 @@ +import 'package:oktoast/oktoast.dart'; +import 'package:permission_handler/permission_handler.dart'; + +/// 请求权限工具 + +/// 请求位置权限 +Future reqPositionPermission() async { + final status = await Permission.location.request(); + if (status == PermissionStatus.granted) { + return true; + } else { + showToast('需要定位权限,请去设置中开启'); + return false; + } +} diff --git a/lib/utils/route_util.dart b/lib/utils/route_util.dart new file mode 100644 index 0000000..3d8a6a6 --- /dev/null +++ b/lib/utils/route_util.dart @@ -0,0 +1,22 @@ +import 'package:base_app/common/common.dart'; +import 'package:flutter/material.dart'; + +class RouteUtil { + // 去主页 + static void goMain(BuildContext context) { + pushReplacementNamed(context, BaseConstant.routeMain); + } + + // 去登录页 + static void goLogin(BuildContext context) { + pushReplacementNamed(context, BaseConstant.routeLogin); + } + + static void pushNamed(BuildContext context, String pageName) { + Navigator.of(context).pushNamed(pageName); + } + + static void pushReplacementNamed(BuildContext context, String pageName) { + Navigator.of(context).pushReplacementNamed(pageName); + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/route/fadeRoute.dart b/lib/ui/widgets/common/route/fadeRoute.dart new file mode 100644 index 0000000..09cda1e --- /dev/null +++ b/lib/ui/widgets/common/route/fadeRoute.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; + +///FadeRoute是自定义的切换过度动画(渐隐渐现) +class FadeRoute extends PageRouteBuilder { + final Widget page; + FadeRoute({this.page}): super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) =>page,transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) =>FadeTransition( + opacity: animation, + child: child, + ), + ); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/route/popRoute.dart b/lib/ui/widgets/common/route/popRoute.dart new file mode 100644 index 0000000..e779cd1 --- /dev/null +++ b/lib/ui/widgets/common/route/popRoute.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class PopRoute extends PopupRoute{ + final Duration _duration = Duration(milliseconds: 300); + Widget child; + + PopRoute({@required this.child}); + + @override + Color get barrierColor => null; + + @override + bool get barrierDismissible => true; + + @override + String get barrierLabel => null; + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + return child; + } + + @override + Duration get transitionDuration => _duration; + +} \ No newline at end of file diff --git a/lib/ui/widgets/common/web_scaffold.dart b/lib/ui/widgets/common/web_scaffold.dart new file mode 100644 index 0000000..3c7efe2 --- /dev/null +++ b/lib/ui/widgets/common/web_scaffold.dart @@ -0,0 +1,173 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; +import 'package:share/share.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +import 'button/likebtn/like_button.dart'; + +class WebScaffold extends StatefulWidget { + const WebScaffold({ + Key key, + this.title, + this.titleId, + this.url, + }) : super(key: key); + + final String title; + final String titleId; + final String url; + + @override + State createState() { + return new WebScaffoldState(); + } +} + +class WebScaffoldState extends State { +// WebViewController _webViewController; +// bool _isShowFloatBtn = false; + + void _onPopSelected(String value) { + String _title = widget.title ?? IntlUtil.getString(context, widget.titleId); + switch (value) { + case "browser": // 浏览 + NavigatorUtil.launchInBrowser(widget.url, title: _title); + break; + case "collection": // 收藏 + break; + case "share": // 分享 + String _url = widget.url; + Share.share('$_title : $_url'); + break; + default: + break; + } + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + centerTitle: true, + actions: [ + LikeButton( + width: 56.0, + duration: Duration(milliseconds: 500), + ), +// new IconButton(icon: new Icon(Icons.more_vert), onPressed: () {}), + new PopupMenuButton( + padding: const EdgeInsets.all(0.0), + onSelected: _onPopSelected, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: "browser", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '浏览器打开', + style: TextStyles.listContent, + ) + ], + ), + ))), +// new PopupMenuItem( +// value: "collection", +// child: ListTile( +// contentPadding: EdgeInsets.all(0.0), +// dense: false, +// title: new Container( +// alignment: Alignment.center, +// child: new Row( +// children: [ +// Icon( +// Icons.collections, +// color: Colours.gray_66, +// size: 22.0, +// ), +// Gaps.hGap10, +// Text( +// '收藏', +// style: TextStyles.listContent, +// ) +// ], +// ), +// ))), + new PopupMenuItem( + value: "share", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.share, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '分享', + style: TextStyles.listContent, + ) + ], + ), + ))), + ]) + ], + ), + body: new WebView( + onWebViewCreated: (WebViewController webViewController) { +// _webViewController = webViewController; +// _webViewController.addListener(() { +// int _scrollY = _webViewController.scrollY.toInt(); +// if (_scrollY < 480 && _isShowFloatBtn) { +// _isShowFloatBtn = false; +// setState(() {}); +// } else if (_scrollY > 480 && !_isShowFloatBtn) { +// _isShowFloatBtn = true; +// setState(() {}); +// } +// }); + }, + initialUrl: widget.url, + javascriptMode: JavascriptMode.unrestricted, + ), +// floatingActionButton: _buildFloatingActionButton(), + ); + } + +// Widget _buildFloatingActionButton() { +// if (_webViewController == null || _webViewController.scrollY < 480) { +// return null; +// } +// return new FloatingActionButton( +// heroTag: widget.title ?? widget.titleId, +// backgroundColor: Theme.of(context).primaryColor, +// child: Icon( +// Icons.keyboard_arrow_up, +// ), +// onPressed: () { +// _webViewController.scrollTop(); +// }); +// } +} diff --git a/lib/ui/widgets/login_page/login_item_widget.dart b/lib/ui/widgets/login_page/login_item_widget.dart new file mode 100644 index 0000000..58a8778 --- /dev/null +++ b/lib/ui/widgets/login_page/login_item_widget.dart @@ -0,0 +1,96 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 登录项 +class LoginItem extends StatefulWidget { + final IconData prefixIcon; // 前方icon + final bool hasSuffixIcon; // 是否要后面的icon + final String hintText; // 提示文字 + final bool autoFocus; // 自动聚焦 + final TextInputType keyboardType; // 键盘类型 + final int maxLength; // 最大程度 + final bool maxLengthEnforced; // 当长度达到限制长度时,是否强制组织输入 + final TextInputAction textInputAction; // 输入action + final TextEditingController controller; // controller + final FocusNode focusNode; //focusNode + final VoidCallback onEditingComplete; // 输入完毕后的回调 + + const LoginItem( + {Key key, + this.prefixIcon, + this.hasSuffixIcon = false, + this.autoFocus = false, + this.keyboardType = TextInputType.text, + this.hintText, + this.maxLength, + this.maxLengthEnforced = true, + this.textInputAction, + this.controller, + this.focusNode, + this.onEditingComplete}) + : super(key: key); + + @override + State createState() { + return LoginItemState(); + } +} + +class LoginItemState extends State { + bool _obscureText; // 是否隐藏原始文字 // 密码用 + + @override + void initState() { + super.initState(); + _obscureText = widget.hasSuffixIcon; + } + + @override + Widget build(BuildContext context) { + return new Row( + children: [ + new IconButton( + iconSize: 28, + icon: new Icon( + widget.prefixIcon, + color: Theme.of(context).primaryColor, + ), + onPressed: () {}), + Gaps.hGap5, + new Expanded( + child: new TextField( + textInputAction: widget.textInputAction, + focusNode: widget.focusNode, + onEditingComplete: widget.onEditingComplete, + obscureText: _obscureText, + controller: widget.controller, + maxLength: widget.maxLength, + maxLengthEnforced: widget.maxLengthEnforced, + style: new TextStyle(color: Colours.gray_66, fontSize: 14), + decoration: new InputDecoration( + hintText: widget.hintText, + hintStyle: new TextStyle(color: Colours.gray_99, fontSize: 14), + suffixIcon: widget.hasSuffixIcon + ? new IconButton( + icon: new Icon( + _obscureText + ? Icons.visibility + : Icons.visibility_off, + color: Colours.gray_66, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }) + : null, + focusedBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + enabledBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + )), + ), + ], + ); + } +} diff --git a/lib/utils/encrypt_helper.dart b/lib/utils/encrypt_helper.dart new file mode 100644 index 0000000..caf7196 --- /dev/null +++ b/lib/utils/encrypt_helper.dart @@ -0,0 +1,30 @@ +import 'package:encrypt/encrypt.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +import 'dart:async'; +import 'package:flutter/services.dart' show rootBundle; + +/// RSA加密工具 +final parser = RSAKeyParser(); + +class EncryptHelper { + /// 加密 + ///[src] 待加密字符串 + static Future encode(String src) async { + String publicKeyString = await rootBundle.loadString('keys/public_key.pem'); + RSAPublicKey publicKey = parser.parse(publicKeyString); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + return encrypter.encrypt(src).base64; + } + + /// 解密 + /// [decoded] 待解密字符串 + static Future decode(String decoded) async { + String privateKeyString = + await rootBundle.loadString('keys/private_key.pem'); + + final privateKey = parser.parse(privateKeyString); + + final encrypter = Encrypter(RSA(privateKey: privateKey)); + return encrypter.decrypt(Encrypted.fromBase64(decoded)); + } +} diff --git a/lib/utils/http_utils.dart b/lib/utils/http_utils.dart new file mode 100644 index 0000000..319ca63 --- /dev/null +++ b/lib/utils/http_utils.dart @@ -0,0 +1,30 @@ +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/models/common/version_model.dart'; + +/// 模拟网络请求数据 +class HttpUtils { + Future getSplash() { + return Future.delayed(Duration(milliseconds: 500), () { + return SplashModel( + title: 'Flutter 常用工具类库', + content: 'Flutter 常用工具类库', + url: 'https://www.jianshu.com/p/425a7ff9d66e', + imgUrl: + 'https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_common_utils_a.png', + ); + }); + } + + /// 该地址可能无法下载,请自行更换可测试apk地址。 + Future getVersion() async { + return Future.delayed(Duration(milliseconds: 500), () { + return VersionModel( + title: '有新版本v1.1.0,快去更新吧!', + content: '1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~', + url: + 'https://raw.githubusercontent.com/Sky24n/Doc/master/apks/flutter_wanandroid.apk', + version: '1.0.0', + ); + }); + } +} diff --git a/lib/utils/login_utils.dart b/lib/utils/login_utils.dart new file mode 100644 index 0000000..af31546 --- /dev/null +++ b/lib/utils/login_utils.dart @@ -0,0 +1,47 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flustars/flustars.dart'; + +/// 登录工具类 +class LoginUtils { + /// 判断用户是否已登录 + static Future isLogin() async { + // 1. 先判断token是否在 + bool hasToken = + ObjectUtil.isNotEmpty(SpUtil.getString(BaseConstant.keyAppToken)); + if (hasToken) { + // 2.用token去获取用户信息,有信息认为已登录,否则为未登录 + UserRepository userRepository = new UserRepository(); + UserModel user = await userRepository.getUserInfo(); + if (user == null) { + // 未登录的尝试自动登录,返回自动登录结果 + return await autoLogin(); + } else { + return true; + } + } else { + return hasToken; + } + } + + // 自动登录 + static Future autoLogin() async { + // 取用户名和密码自动登录 + String username = SpUtil.getString(BaseConstant.keyAccount); + String password = SpUtil.getString(BaseConstant.keyPassword); + UserRepository userRepository = new UserRepository(); + LoginReq req = new LoginReq(username, password); + try { + UserModel model = await userRepository.login(req); + if (model != null) { + return true; + } else { + return false; + } + } catch (error) { + return false; + } + } +} diff --git a/lib/utils/map_utils.dart b/lib/utils/map_utils.dart new file mode 100644 index 0000000..dc6029d --- /dev/null +++ b/lib/utils/map_utils.dart @@ -0,0 +1,72 @@ +import 'dart:math'; + +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; + +/// 地图工具类 +class MapUtils { + ///计算两点距离 + ///[start] 第一个点坐标[lng,lat] + ///[end]第二个点坐标[lng,lat] + static double calculateDistance(start, end) { + if ((start != null) || (end != null)) { + double d1 = 0.01745329251994329; + double d2 = start[0]; //lng + double d3 = start[1]; //lat + double d4 = end[0]; //lng + double d5 = end[1]; //lat + d2 *= d1; + d3 *= d1; + d4 *= d1; + d5 *= d1; + double d6 = sin(d2); + double d7 = sin(d3); + double d8 = cos(d2); + double d9 = cos(d3); + double d10 = sin(d4); + double d11 = sin(d5); + double d12 = cos(d4); + double d13 = cos(d5); + List arrayOfDouble1 = List(3); + List arrayOfDouble2 = List(3); + arrayOfDouble1[0] = (d9 * d8); + arrayOfDouble1[1] = (d9 * d6); + arrayOfDouble1[2] = d7; + arrayOfDouble2[0] = (d13 * d12); + arrayOfDouble2[1] = (d13 * d10); + arrayOfDouble2[2] = d11; + double d14 = sqrt((arrayOfDouble1[0] - arrayOfDouble2[0]) * + (arrayOfDouble1[0] - arrayOfDouble2[0]) + + (arrayOfDouble1[1] - arrayOfDouble2[1]) * + (arrayOfDouble1[1] - arrayOfDouble2[1]) + + (arrayOfDouble1[2] - arrayOfDouble2[2]) * + (arrayOfDouble1[2] - arrayOfDouble2[2])); + print((asin(d14 / 2.0) * 12742001.579854401)); + return (asin(d14 / 2.0) * 12742001.579854401).abs(); + } else { + return 0.0; + } + } +} + +/// 获取随机坐标 +mixin NextLatLng { + final random = Random(); + + LatLng getNextLatLng({LatLng center}) { + center ??= LatLng(39.90960, 116.397228); + return LatLng( + center.latitude + random.nextDouble(), + center.longitude + random.nextDouble(), + ); + } + + List getNextBatchLatLng(int count) { + return [ + for (int i = 0; i < count; i++) + LatLng( + 39.90960 + random.nextDouble() * 4, + 116.397228 + random.nextDouble() * 4, + ) + ]; + } +} diff --git a/lib/utils/navigator_util.dart b/lib/utils/navigator_util.dart new file mode 100644 index 0000000..00c6bc1 --- /dev/null +++ b/lib/utils/navigator_util.dart @@ -0,0 +1,52 @@ +import 'package:base_app/ui/pages/user/user_login_page.dart'; +import 'package:base_app/ui/widgets/common/web_scaffold.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class NavigatorUtil { + // 打开页面 + static void pushPage( + BuildContext context, + Widget page, { + String pageName, + bool needLogin = false, + }) async { + if (context == null || page == null) return; + bool isLogin = await LoginUtils.isLogin(); + if (needLogin && isLogin == false) { + pushPage(context, UserLoginPage()); + return; + } + Navigator.push( + context, new CupertinoPageRoute(builder: (ctx) => page)); + } + + // 打开网页 + static void pushWeb(BuildContext context, + {String title, String titleId, String url}) { + if (context == null || ObjectUtil.isEmpty(url)) return; + if (url.endsWith(".apk")) { + launchInBrowser(url, title: title ?? titleId); + } else { + Navigator.push( + context, + new CupertinoPageRoute( + builder: (ctx) => new WebScaffold( + title: title, + titleId: titleId, + url: url, + ))); + } + } + + // 打开浏览器 + static Future launchInBrowser(String url, {String title}) async { + if (await canLaunch(url)) { + await launch(url, forceSafariVC: false, forceWebView: false); + } else { + throw 'Could not launch $url'; + } + } +} diff --git a/lib/utils/permission_util.dart b/lib/utils/permission_util.dart new file mode 100644 index 0000000..6e75801 --- /dev/null +++ b/lib/utils/permission_util.dart @@ -0,0 +1,15 @@ +import 'package:oktoast/oktoast.dart'; +import 'package:permission_handler/permission_handler.dart'; + +/// 请求权限工具 + +/// 请求位置权限 +Future reqPositionPermission() async { + final status = await Permission.location.request(); + if (status == PermissionStatus.granted) { + return true; + } else { + showToast('需要定位权限,请去设置中开启'); + return false; + } +} diff --git a/lib/utils/route_util.dart b/lib/utils/route_util.dart new file mode 100644 index 0000000..3d8a6a6 --- /dev/null +++ b/lib/utils/route_util.dart @@ -0,0 +1,22 @@ +import 'package:base_app/common/common.dart'; +import 'package:flutter/material.dart'; + +class RouteUtil { + // 去主页 + static void goMain(BuildContext context) { + pushReplacementNamed(context, BaseConstant.routeMain); + } + + // 去登录页 + static void goLogin(BuildContext context) { + pushReplacementNamed(context, BaseConstant.routeLogin); + } + + static void pushNamed(BuildContext context, String pageName) { + Navigator.of(context).pushNamed(pageName); + } + + static void pushReplacementNamed(BuildContext context, String pageName) { + Navigator.of(context).pushReplacementNamed(pageName); + } +} diff --git a/lib/utils/util_index.dart b/lib/utils/util_index.dart new file mode 100644 index 0000000..b240611 --- /dev/null +++ b/lib/utils/util_index.dart @@ -0,0 +1,9 @@ +export 'navigator_util.dart'; +export 'login_utils.dart'; +export 'http_utils.dart'; +export 'encrypt_helper.dart'; +export 'map_utils.dart'; +export 'navigator_util.dart'; +export 'route_util.dart'; +export 'utils.dart'; +export 'permission_util.dart'; diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/route/fadeRoute.dart b/lib/ui/widgets/common/route/fadeRoute.dart new file mode 100644 index 0000000..09cda1e --- /dev/null +++ b/lib/ui/widgets/common/route/fadeRoute.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; + +///FadeRoute是自定义的切换过度动画(渐隐渐现) +class FadeRoute extends PageRouteBuilder { + final Widget page; + FadeRoute({this.page}): super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) =>page,transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) =>FadeTransition( + opacity: animation, + child: child, + ), + ); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/route/popRoute.dart b/lib/ui/widgets/common/route/popRoute.dart new file mode 100644 index 0000000..e779cd1 --- /dev/null +++ b/lib/ui/widgets/common/route/popRoute.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class PopRoute extends PopupRoute{ + final Duration _duration = Duration(milliseconds: 300); + Widget child; + + PopRoute({@required this.child}); + + @override + Color get barrierColor => null; + + @override + bool get barrierDismissible => true; + + @override + String get barrierLabel => null; + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + return child; + } + + @override + Duration get transitionDuration => _duration; + +} \ No newline at end of file diff --git a/lib/ui/widgets/common/web_scaffold.dart b/lib/ui/widgets/common/web_scaffold.dart new file mode 100644 index 0000000..3c7efe2 --- /dev/null +++ b/lib/ui/widgets/common/web_scaffold.dart @@ -0,0 +1,173 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; +import 'package:share/share.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +import 'button/likebtn/like_button.dart'; + +class WebScaffold extends StatefulWidget { + const WebScaffold({ + Key key, + this.title, + this.titleId, + this.url, + }) : super(key: key); + + final String title; + final String titleId; + final String url; + + @override + State createState() { + return new WebScaffoldState(); + } +} + +class WebScaffoldState extends State { +// WebViewController _webViewController; +// bool _isShowFloatBtn = false; + + void _onPopSelected(String value) { + String _title = widget.title ?? IntlUtil.getString(context, widget.titleId); + switch (value) { + case "browser": // 浏览 + NavigatorUtil.launchInBrowser(widget.url, title: _title); + break; + case "collection": // 收藏 + break; + case "share": // 分享 + String _url = widget.url; + Share.share('$_title : $_url'); + break; + default: + break; + } + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + centerTitle: true, + actions: [ + LikeButton( + width: 56.0, + duration: Duration(milliseconds: 500), + ), +// new IconButton(icon: new Icon(Icons.more_vert), onPressed: () {}), + new PopupMenuButton( + padding: const EdgeInsets.all(0.0), + onSelected: _onPopSelected, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: "browser", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '浏览器打开', + style: TextStyles.listContent, + ) + ], + ), + ))), +// new PopupMenuItem( +// value: "collection", +// child: ListTile( +// contentPadding: EdgeInsets.all(0.0), +// dense: false, +// title: new Container( +// alignment: Alignment.center, +// child: new Row( +// children: [ +// Icon( +// Icons.collections, +// color: Colours.gray_66, +// size: 22.0, +// ), +// Gaps.hGap10, +// Text( +// '收藏', +// style: TextStyles.listContent, +// ) +// ], +// ), +// ))), + new PopupMenuItem( + value: "share", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.share, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '分享', + style: TextStyles.listContent, + ) + ], + ), + ))), + ]) + ], + ), + body: new WebView( + onWebViewCreated: (WebViewController webViewController) { +// _webViewController = webViewController; +// _webViewController.addListener(() { +// int _scrollY = _webViewController.scrollY.toInt(); +// if (_scrollY < 480 && _isShowFloatBtn) { +// _isShowFloatBtn = false; +// setState(() {}); +// } else if (_scrollY > 480 && !_isShowFloatBtn) { +// _isShowFloatBtn = true; +// setState(() {}); +// } +// }); + }, + initialUrl: widget.url, + javascriptMode: JavascriptMode.unrestricted, + ), +// floatingActionButton: _buildFloatingActionButton(), + ); + } + +// Widget _buildFloatingActionButton() { +// if (_webViewController == null || _webViewController.scrollY < 480) { +// return null; +// } +// return new FloatingActionButton( +// heroTag: widget.title ?? widget.titleId, +// backgroundColor: Theme.of(context).primaryColor, +// child: Icon( +// Icons.keyboard_arrow_up, +// ), +// onPressed: () { +// _webViewController.scrollTop(); +// }); +// } +} diff --git a/lib/ui/widgets/login_page/login_item_widget.dart b/lib/ui/widgets/login_page/login_item_widget.dart new file mode 100644 index 0000000..58a8778 --- /dev/null +++ b/lib/ui/widgets/login_page/login_item_widget.dart @@ -0,0 +1,96 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 登录项 +class LoginItem extends StatefulWidget { + final IconData prefixIcon; // 前方icon + final bool hasSuffixIcon; // 是否要后面的icon + final String hintText; // 提示文字 + final bool autoFocus; // 自动聚焦 + final TextInputType keyboardType; // 键盘类型 + final int maxLength; // 最大程度 + final bool maxLengthEnforced; // 当长度达到限制长度时,是否强制组织输入 + final TextInputAction textInputAction; // 输入action + final TextEditingController controller; // controller + final FocusNode focusNode; //focusNode + final VoidCallback onEditingComplete; // 输入完毕后的回调 + + const LoginItem( + {Key key, + this.prefixIcon, + this.hasSuffixIcon = false, + this.autoFocus = false, + this.keyboardType = TextInputType.text, + this.hintText, + this.maxLength, + this.maxLengthEnforced = true, + this.textInputAction, + this.controller, + this.focusNode, + this.onEditingComplete}) + : super(key: key); + + @override + State createState() { + return LoginItemState(); + } +} + +class LoginItemState extends State { + bool _obscureText; // 是否隐藏原始文字 // 密码用 + + @override + void initState() { + super.initState(); + _obscureText = widget.hasSuffixIcon; + } + + @override + Widget build(BuildContext context) { + return new Row( + children: [ + new IconButton( + iconSize: 28, + icon: new Icon( + widget.prefixIcon, + color: Theme.of(context).primaryColor, + ), + onPressed: () {}), + Gaps.hGap5, + new Expanded( + child: new TextField( + textInputAction: widget.textInputAction, + focusNode: widget.focusNode, + onEditingComplete: widget.onEditingComplete, + obscureText: _obscureText, + controller: widget.controller, + maxLength: widget.maxLength, + maxLengthEnforced: widget.maxLengthEnforced, + style: new TextStyle(color: Colours.gray_66, fontSize: 14), + decoration: new InputDecoration( + hintText: widget.hintText, + hintStyle: new TextStyle(color: Colours.gray_99, fontSize: 14), + suffixIcon: widget.hasSuffixIcon + ? new IconButton( + icon: new Icon( + _obscureText + ? Icons.visibility + : Icons.visibility_off, + color: Colours.gray_66, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }) + : null, + focusedBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + enabledBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + )), + ), + ], + ); + } +} diff --git a/lib/utils/encrypt_helper.dart b/lib/utils/encrypt_helper.dart new file mode 100644 index 0000000..caf7196 --- /dev/null +++ b/lib/utils/encrypt_helper.dart @@ -0,0 +1,30 @@ +import 'package:encrypt/encrypt.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +import 'dart:async'; +import 'package:flutter/services.dart' show rootBundle; + +/// RSA加密工具 +final parser = RSAKeyParser(); + +class EncryptHelper { + /// 加密 + ///[src] 待加密字符串 + static Future encode(String src) async { + String publicKeyString = await rootBundle.loadString('keys/public_key.pem'); + RSAPublicKey publicKey = parser.parse(publicKeyString); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + return encrypter.encrypt(src).base64; + } + + /// 解密 + /// [decoded] 待解密字符串 + static Future decode(String decoded) async { + String privateKeyString = + await rootBundle.loadString('keys/private_key.pem'); + + final privateKey = parser.parse(privateKeyString); + + final encrypter = Encrypter(RSA(privateKey: privateKey)); + return encrypter.decrypt(Encrypted.fromBase64(decoded)); + } +} diff --git a/lib/utils/http_utils.dart b/lib/utils/http_utils.dart new file mode 100644 index 0000000..319ca63 --- /dev/null +++ b/lib/utils/http_utils.dart @@ -0,0 +1,30 @@ +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/models/common/version_model.dart'; + +/// 模拟网络请求数据 +class HttpUtils { + Future getSplash() { + return Future.delayed(Duration(milliseconds: 500), () { + return SplashModel( + title: 'Flutter 常用工具类库', + content: 'Flutter 常用工具类库', + url: 'https://www.jianshu.com/p/425a7ff9d66e', + imgUrl: + 'https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_common_utils_a.png', + ); + }); + } + + /// 该地址可能无法下载,请自行更换可测试apk地址。 + Future getVersion() async { + return Future.delayed(Duration(milliseconds: 500), () { + return VersionModel( + title: '有新版本v1.1.0,快去更新吧!', + content: '1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~', + url: + 'https://raw.githubusercontent.com/Sky24n/Doc/master/apks/flutter_wanandroid.apk', + version: '1.0.0', + ); + }); + } +} diff --git a/lib/utils/login_utils.dart b/lib/utils/login_utils.dart new file mode 100644 index 0000000..af31546 --- /dev/null +++ b/lib/utils/login_utils.dart @@ -0,0 +1,47 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flustars/flustars.dart'; + +/// 登录工具类 +class LoginUtils { + /// 判断用户是否已登录 + static Future isLogin() async { + // 1. 先判断token是否在 + bool hasToken = + ObjectUtil.isNotEmpty(SpUtil.getString(BaseConstant.keyAppToken)); + if (hasToken) { + // 2.用token去获取用户信息,有信息认为已登录,否则为未登录 + UserRepository userRepository = new UserRepository(); + UserModel user = await userRepository.getUserInfo(); + if (user == null) { + // 未登录的尝试自动登录,返回自动登录结果 + return await autoLogin(); + } else { + return true; + } + } else { + return hasToken; + } + } + + // 自动登录 + static Future autoLogin() async { + // 取用户名和密码自动登录 + String username = SpUtil.getString(BaseConstant.keyAccount); + String password = SpUtil.getString(BaseConstant.keyPassword); + UserRepository userRepository = new UserRepository(); + LoginReq req = new LoginReq(username, password); + try { + UserModel model = await userRepository.login(req); + if (model != null) { + return true; + } else { + return false; + } + } catch (error) { + return false; + } + } +} diff --git a/lib/utils/map_utils.dart b/lib/utils/map_utils.dart new file mode 100644 index 0000000..dc6029d --- /dev/null +++ b/lib/utils/map_utils.dart @@ -0,0 +1,72 @@ +import 'dart:math'; + +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; + +/// 地图工具类 +class MapUtils { + ///计算两点距离 + ///[start] 第一个点坐标[lng,lat] + ///[end]第二个点坐标[lng,lat] + static double calculateDistance(start, end) { + if ((start != null) || (end != null)) { + double d1 = 0.01745329251994329; + double d2 = start[0]; //lng + double d3 = start[1]; //lat + double d4 = end[0]; //lng + double d5 = end[1]; //lat + d2 *= d1; + d3 *= d1; + d4 *= d1; + d5 *= d1; + double d6 = sin(d2); + double d7 = sin(d3); + double d8 = cos(d2); + double d9 = cos(d3); + double d10 = sin(d4); + double d11 = sin(d5); + double d12 = cos(d4); + double d13 = cos(d5); + List arrayOfDouble1 = List(3); + List arrayOfDouble2 = List(3); + arrayOfDouble1[0] = (d9 * d8); + arrayOfDouble1[1] = (d9 * d6); + arrayOfDouble1[2] = d7; + arrayOfDouble2[0] = (d13 * d12); + arrayOfDouble2[1] = (d13 * d10); + arrayOfDouble2[2] = d11; + double d14 = sqrt((arrayOfDouble1[0] - arrayOfDouble2[0]) * + (arrayOfDouble1[0] - arrayOfDouble2[0]) + + (arrayOfDouble1[1] - arrayOfDouble2[1]) * + (arrayOfDouble1[1] - arrayOfDouble2[1]) + + (arrayOfDouble1[2] - arrayOfDouble2[2]) * + (arrayOfDouble1[2] - arrayOfDouble2[2])); + print((asin(d14 / 2.0) * 12742001.579854401)); + return (asin(d14 / 2.0) * 12742001.579854401).abs(); + } else { + return 0.0; + } + } +} + +/// 获取随机坐标 +mixin NextLatLng { + final random = Random(); + + LatLng getNextLatLng({LatLng center}) { + center ??= LatLng(39.90960, 116.397228); + return LatLng( + center.latitude + random.nextDouble(), + center.longitude + random.nextDouble(), + ); + } + + List getNextBatchLatLng(int count) { + return [ + for (int i = 0; i < count; i++) + LatLng( + 39.90960 + random.nextDouble() * 4, + 116.397228 + random.nextDouble() * 4, + ) + ]; + } +} diff --git a/lib/utils/navigator_util.dart b/lib/utils/navigator_util.dart new file mode 100644 index 0000000..00c6bc1 --- /dev/null +++ b/lib/utils/navigator_util.dart @@ -0,0 +1,52 @@ +import 'package:base_app/ui/pages/user/user_login_page.dart'; +import 'package:base_app/ui/widgets/common/web_scaffold.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class NavigatorUtil { + // 打开页面 + static void pushPage( + BuildContext context, + Widget page, { + String pageName, + bool needLogin = false, + }) async { + if (context == null || page == null) return; + bool isLogin = await LoginUtils.isLogin(); + if (needLogin && isLogin == false) { + pushPage(context, UserLoginPage()); + return; + } + Navigator.push( + context, new CupertinoPageRoute(builder: (ctx) => page)); + } + + // 打开网页 + static void pushWeb(BuildContext context, + {String title, String titleId, String url}) { + if (context == null || ObjectUtil.isEmpty(url)) return; + if (url.endsWith(".apk")) { + launchInBrowser(url, title: title ?? titleId); + } else { + Navigator.push( + context, + new CupertinoPageRoute( + builder: (ctx) => new WebScaffold( + title: title, + titleId: titleId, + url: url, + ))); + } + } + + // 打开浏览器 + static Future launchInBrowser(String url, {String title}) async { + if (await canLaunch(url)) { + await launch(url, forceSafariVC: false, forceWebView: false); + } else { + throw 'Could not launch $url'; + } + } +} diff --git a/lib/utils/permission_util.dart b/lib/utils/permission_util.dart new file mode 100644 index 0000000..6e75801 --- /dev/null +++ b/lib/utils/permission_util.dart @@ -0,0 +1,15 @@ +import 'package:oktoast/oktoast.dart'; +import 'package:permission_handler/permission_handler.dart'; + +/// 请求权限工具 + +/// 请求位置权限 +Future reqPositionPermission() async { + final status = await Permission.location.request(); + if (status == PermissionStatus.granted) { + return true; + } else { + showToast('需要定位权限,请去设置中开启'); + return false; + } +} diff --git a/lib/utils/route_util.dart b/lib/utils/route_util.dart new file mode 100644 index 0000000..3d8a6a6 --- /dev/null +++ b/lib/utils/route_util.dart @@ -0,0 +1,22 @@ +import 'package:base_app/common/common.dart'; +import 'package:flutter/material.dart'; + +class RouteUtil { + // 去主页 + static void goMain(BuildContext context) { + pushReplacementNamed(context, BaseConstant.routeMain); + } + + // 去登录页 + static void goLogin(BuildContext context) { + pushReplacementNamed(context, BaseConstant.routeLogin); + } + + static void pushNamed(BuildContext context, String pageName) { + Navigator.of(context).pushNamed(pageName); + } + + static void pushReplacementNamed(BuildContext context, String pageName) { + Navigator.of(context).pushReplacementNamed(pageName); + } +} diff --git a/lib/utils/util_index.dart b/lib/utils/util_index.dart new file mode 100644 index 0000000..b240611 --- /dev/null +++ b/lib/utils/util_index.dart @@ -0,0 +1,9 @@ +export 'navigator_util.dart'; +export 'login_utils.dart'; +export 'http_utils.dart'; +export 'encrypt_helper.dart'; +export 'map_utils.dart'; +export 'navigator_util.dart'; +export 'route_util.dart'; +export 'utils.dart'; +export 'permission_util.dart'; diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart new file mode 100644 index 0000000..f2f8f38 --- /dev/null +++ b/lib/utils/utils.dart @@ -0,0 +1,152 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; +import 'dart:convert' as convert; + +/// 工具类 +class Utils { + // 是否需要登录 + static bool isNeedLogin(String pageId) { + return false; + } + + /// 显示提示信息,在屏幕下方 + static void showSnackBar(BuildContext context, String msg) { + Scaffold.of(context).showSnackBar( + SnackBar(content: Text("$msg")), + ); + } + + // 加载文本资源 + Future loadAsset(String filename) async { + return await rootBundle.loadString('assets/data/$filename'); + } + + /// 获取图片路径 + /// [name] 图片名称 不含后缀,assets/images文件夹下地图图片 + /// [format] 图片格式(后缀,如png,jpg等) + static String getImgPath(String name, {String format: 'png'}) { + return 'assets/images/$name.$format'; + } + + /// 获取文件名称 + /// [urlPath] 文件路径 + static String getFileName(String urlPath) { + if (ObjectUtil.isEmpty(urlPath)) return ''; + List listStr = urlPath.split("/"); + String name = listStr[listStr.length - 1]; + return name; + } + + /// 获取字符串对应拼音的首字母的大写字母 + /// [str] 待处理字符串 + static String getPinyin(String str) { + return PinyinHelper.getShortPinyin(str).substring(0, 1).toUpperCase(); + } + + /// 获取圆圈的背景 + static Color getCircleBg(String str) { + String pinyin = getPinyin(str); + return getCircleAvatarBg(pinyin); + } + + /// 获取头像背景颜色 + /// [key] 对照表中的key + static Color getCircleAvatarBg(String key) { + return circleAvatarMap[key]; + } + + static Color getChipBgColor(String name) { + String pinyin = PinyinHelper.getFirstWordPinyin(name); + pinyin = pinyin.substring(0, 1).toUpperCase(); + return nameToColor(pinyin); + } + + static Color nameToColor(String name) { + // assert(name.length > 1); + final int hash = name.hashCode & 0xffff; + final double hue = (360.0 * hash / (1 << 15)) % 360.0; + return HSVColor.fromAHSV(1.0, hue, 0.4, 0.90).toColor(); + } + + static String getTimeLine(BuildContext context, int timeMillis) { +// LogUtil.e("countryCode: " + +// Localizations.localeOf(context).countryCode + +// " languageCode: " + +// Localizations.localeOf(context).languageCode); + return TimelineUtil.format(timeMillis, + locale: Localizations.localeOf(context).languageCode, + dayFormat: DayFormat.Common); + } + + /// 计算标题字号 + /// [title] 标题 + static double getTitleFontSize(String title) { + // 小于10个字,18号字体 + if (ObjectUtil.isEmpty(title) || title.length < 10) { + return 18.0; + } + int count = 0; + List list = title.split(""); + for (int i = 0, length = list.length; i < length; i++) { + String ss = list[i]; + if (RegexUtil.isZh(ss)) { + count++; + } + } + //10个汉字或16个字符以上,14号字 + return (count >= 10 || title.length > 16) ? 14.0 : 18.0; + } + + /// 判断升级状态,如果远程版本小于等于当前按本,返回0 不升级, + /// 如果返回 1 升级 + /// > x 强升 + static int getUpdateStatus(String version, {String local}) { + if (ObjectUtil.isEmpty(version)) return 0; + String locVersion = local ?? AppConfig.version; + int remote = int.tryParse(version.replaceAll('.', '')); + int loc = int.tryParse(locVersion.replaceAll('.', '')); + if (remote <= loc) { + return 0; + } else { + return remote - loc; + } + } + + /// 获取加载状态 + static int getLoadStatus(bool hasError, List data) { + if (hasError) return LoadStatus.fail; + if (data == null) { + // data为空,加载中 + return LoadStatus.loading; + } else if (data.isEmpty) { + // data为空数组,返回空 + return LoadStatus.empty; + } else { + // + return LoadStatus.success; + } + } + + /// 字符串转列表 + /// [str] 待转字符串 如:[1,2,3,4,5] + static List strToList(String str) { + if (str == '') { + str = "[]"; + } + List list = convert.jsonDecode(str); + print(list); + return list; + } + + /// 列表转字符串 + /// [list] 待转列表 + static String listToStr(List list) { + String str = convert.jsonEncode(list); + print(str); + return str; + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/route/fadeRoute.dart b/lib/ui/widgets/common/route/fadeRoute.dart new file mode 100644 index 0000000..09cda1e --- /dev/null +++ b/lib/ui/widgets/common/route/fadeRoute.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; + +///FadeRoute是自定义的切换过度动画(渐隐渐现) +class FadeRoute extends PageRouteBuilder { + final Widget page; + FadeRoute({this.page}): super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) =>page,transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) =>FadeTransition( + opacity: animation, + child: child, + ), + ); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/route/popRoute.dart b/lib/ui/widgets/common/route/popRoute.dart new file mode 100644 index 0000000..e779cd1 --- /dev/null +++ b/lib/ui/widgets/common/route/popRoute.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class PopRoute extends PopupRoute{ + final Duration _duration = Duration(milliseconds: 300); + Widget child; + + PopRoute({@required this.child}); + + @override + Color get barrierColor => null; + + @override + bool get barrierDismissible => true; + + @override + String get barrierLabel => null; + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + return child; + } + + @override + Duration get transitionDuration => _duration; + +} \ No newline at end of file diff --git a/lib/ui/widgets/common/web_scaffold.dart b/lib/ui/widgets/common/web_scaffold.dart new file mode 100644 index 0000000..3c7efe2 --- /dev/null +++ b/lib/ui/widgets/common/web_scaffold.dart @@ -0,0 +1,173 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; +import 'package:share/share.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +import 'button/likebtn/like_button.dart'; + +class WebScaffold extends StatefulWidget { + const WebScaffold({ + Key key, + this.title, + this.titleId, + this.url, + }) : super(key: key); + + final String title; + final String titleId; + final String url; + + @override + State createState() { + return new WebScaffoldState(); + } +} + +class WebScaffoldState extends State { +// WebViewController _webViewController; +// bool _isShowFloatBtn = false; + + void _onPopSelected(String value) { + String _title = widget.title ?? IntlUtil.getString(context, widget.titleId); + switch (value) { + case "browser": // 浏览 + NavigatorUtil.launchInBrowser(widget.url, title: _title); + break; + case "collection": // 收藏 + break; + case "share": // 分享 + String _url = widget.url; + Share.share('$_title : $_url'); + break; + default: + break; + } + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + centerTitle: true, + actions: [ + LikeButton( + width: 56.0, + duration: Duration(milliseconds: 500), + ), +// new IconButton(icon: new Icon(Icons.more_vert), onPressed: () {}), + new PopupMenuButton( + padding: const EdgeInsets.all(0.0), + onSelected: _onPopSelected, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: "browser", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '浏览器打开', + style: TextStyles.listContent, + ) + ], + ), + ))), +// new PopupMenuItem( +// value: "collection", +// child: ListTile( +// contentPadding: EdgeInsets.all(0.0), +// dense: false, +// title: new Container( +// alignment: Alignment.center, +// child: new Row( +// children: [ +// Icon( +// Icons.collections, +// color: Colours.gray_66, +// size: 22.0, +// ), +// Gaps.hGap10, +// Text( +// '收藏', +// style: TextStyles.listContent, +// ) +// ], +// ), +// ))), + new PopupMenuItem( + value: "share", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.share, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '分享', + style: TextStyles.listContent, + ) + ], + ), + ))), + ]) + ], + ), + body: new WebView( + onWebViewCreated: (WebViewController webViewController) { +// _webViewController = webViewController; +// _webViewController.addListener(() { +// int _scrollY = _webViewController.scrollY.toInt(); +// if (_scrollY < 480 && _isShowFloatBtn) { +// _isShowFloatBtn = false; +// setState(() {}); +// } else if (_scrollY > 480 && !_isShowFloatBtn) { +// _isShowFloatBtn = true; +// setState(() {}); +// } +// }); + }, + initialUrl: widget.url, + javascriptMode: JavascriptMode.unrestricted, + ), +// floatingActionButton: _buildFloatingActionButton(), + ); + } + +// Widget _buildFloatingActionButton() { +// if (_webViewController == null || _webViewController.scrollY < 480) { +// return null; +// } +// return new FloatingActionButton( +// heroTag: widget.title ?? widget.titleId, +// backgroundColor: Theme.of(context).primaryColor, +// child: Icon( +// Icons.keyboard_arrow_up, +// ), +// onPressed: () { +// _webViewController.scrollTop(); +// }); +// } +} diff --git a/lib/ui/widgets/login_page/login_item_widget.dart b/lib/ui/widgets/login_page/login_item_widget.dart new file mode 100644 index 0000000..58a8778 --- /dev/null +++ b/lib/ui/widgets/login_page/login_item_widget.dart @@ -0,0 +1,96 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 登录项 +class LoginItem extends StatefulWidget { + final IconData prefixIcon; // 前方icon + final bool hasSuffixIcon; // 是否要后面的icon + final String hintText; // 提示文字 + final bool autoFocus; // 自动聚焦 + final TextInputType keyboardType; // 键盘类型 + final int maxLength; // 最大程度 + final bool maxLengthEnforced; // 当长度达到限制长度时,是否强制组织输入 + final TextInputAction textInputAction; // 输入action + final TextEditingController controller; // controller + final FocusNode focusNode; //focusNode + final VoidCallback onEditingComplete; // 输入完毕后的回调 + + const LoginItem( + {Key key, + this.prefixIcon, + this.hasSuffixIcon = false, + this.autoFocus = false, + this.keyboardType = TextInputType.text, + this.hintText, + this.maxLength, + this.maxLengthEnforced = true, + this.textInputAction, + this.controller, + this.focusNode, + this.onEditingComplete}) + : super(key: key); + + @override + State createState() { + return LoginItemState(); + } +} + +class LoginItemState extends State { + bool _obscureText; // 是否隐藏原始文字 // 密码用 + + @override + void initState() { + super.initState(); + _obscureText = widget.hasSuffixIcon; + } + + @override + Widget build(BuildContext context) { + return new Row( + children: [ + new IconButton( + iconSize: 28, + icon: new Icon( + widget.prefixIcon, + color: Theme.of(context).primaryColor, + ), + onPressed: () {}), + Gaps.hGap5, + new Expanded( + child: new TextField( + textInputAction: widget.textInputAction, + focusNode: widget.focusNode, + onEditingComplete: widget.onEditingComplete, + obscureText: _obscureText, + controller: widget.controller, + maxLength: widget.maxLength, + maxLengthEnforced: widget.maxLengthEnforced, + style: new TextStyle(color: Colours.gray_66, fontSize: 14), + decoration: new InputDecoration( + hintText: widget.hintText, + hintStyle: new TextStyle(color: Colours.gray_99, fontSize: 14), + suffixIcon: widget.hasSuffixIcon + ? new IconButton( + icon: new Icon( + _obscureText + ? Icons.visibility + : Icons.visibility_off, + color: Colours.gray_66, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }) + : null, + focusedBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + enabledBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + )), + ), + ], + ); + } +} diff --git a/lib/utils/encrypt_helper.dart b/lib/utils/encrypt_helper.dart new file mode 100644 index 0000000..caf7196 --- /dev/null +++ b/lib/utils/encrypt_helper.dart @@ -0,0 +1,30 @@ +import 'package:encrypt/encrypt.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +import 'dart:async'; +import 'package:flutter/services.dart' show rootBundle; + +/// RSA加密工具 +final parser = RSAKeyParser(); + +class EncryptHelper { + /// 加密 + ///[src] 待加密字符串 + static Future encode(String src) async { + String publicKeyString = await rootBundle.loadString('keys/public_key.pem'); + RSAPublicKey publicKey = parser.parse(publicKeyString); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + return encrypter.encrypt(src).base64; + } + + /// 解密 + /// [decoded] 待解密字符串 + static Future decode(String decoded) async { + String privateKeyString = + await rootBundle.loadString('keys/private_key.pem'); + + final privateKey = parser.parse(privateKeyString); + + final encrypter = Encrypter(RSA(privateKey: privateKey)); + return encrypter.decrypt(Encrypted.fromBase64(decoded)); + } +} diff --git a/lib/utils/http_utils.dart b/lib/utils/http_utils.dart new file mode 100644 index 0000000..319ca63 --- /dev/null +++ b/lib/utils/http_utils.dart @@ -0,0 +1,30 @@ +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/models/common/version_model.dart'; + +/// 模拟网络请求数据 +class HttpUtils { + Future getSplash() { + return Future.delayed(Duration(milliseconds: 500), () { + return SplashModel( + title: 'Flutter 常用工具类库', + content: 'Flutter 常用工具类库', + url: 'https://www.jianshu.com/p/425a7ff9d66e', + imgUrl: + 'https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_common_utils_a.png', + ); + }); + } + + /// 该地址可能无法下载,请自行更换可测试apk地址。 + Future getVersion() async { + return Future.delayed(Duration(milliseconds: 500), () { + return VersionModel( + title: '有新版本v1.1.0,快去更新吧!', + content: '1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~', + url: + 'https://raw.githubusercontent.com/Sky24n/Doc/master/apks/flutter_wanandroid.apk', + version: '1.0.0', + ); + }); + } +} diff --git a/lib/utils/login_utils.dart b/lib/utils/login_utils.dart new file mode 100644 index 0000000..af31546 --- /dev/null +++ b/lib/utils/login_utils.dart @@ -0,0 +1,47 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flustars/flustars.dart'; + +/// 登录工具类 +class LoginUtils { + /// 判断用户是否已登录 + static Future isLogin() async { + // 1. 先判断token是否在 + bool hasToken = + ObjectUtil.isNotEmpty(SpUtil.getString(BaseConstant.keyAppToken)); + if (hasToken) { + // 2.用token去获取用户信息,有信息认为已登录,否则为未登录 + UserRepository userRepository = new UserRepository(); + UserModel user = await userRepository.getUserInfo(); + if (user == null) { + // 未登录的尝试自动登录,返回自动登录结果 + return await autoLogin(); + } else { + return true; + } + } else { + return hasToken; + } + } + + // 自动登录 + static Future autoLogin() async { + // 取用户名和密码自动登录 + String username = SpUtil.getString(BaseConstant.keyAccount); + String password = SpUtil.getString(BaseConstant.keyPassword); + UserRepository userRepository = new UserRepository(); + LoginReq req = new LoginReq(username, password); + try { + UserModel model = await userRepository.login(req); + if (model != null) { + return true; + } else { + return false; + } + } catch (error) { + return false; + } + } +} diff --git a/lib/utils/map_utils.dart b/lib/utils/map_utils.dart new file mode 100644 index 0000000..dc6029d --- /dev/null +++ b/lib/utils/map_utils.dart @@ -0,0 +1,72 @@ +import 'dart:math'; + +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; + +/// 地图工具类 +class MapUtils { + ///计算两点距离 + ///[start] 第一个点坐标[lng,lat] + ///[end]第二个点坐标[lng,lat] + static double calculateDistance(start, end) { + if ((start != null) || (end != null)) { + double d1 = 0.01745329251994329; + double d2 = start[0]; //lng + double d3 = start[1]; //lat + double d4 = end[0]; //lng + double d5 = end[1]; //lat + d2 *= d1; + d3 *= d1; + d4 *= d1; + d5 *= d1; + double d6 = sin(d2); + double d7 = sin(d3); + double d8 = cos(d2); + double d9 = cos(d3); + double d10 = sin(d4); + double d11 = sin(d5); + double d12 = cos(d4); + double d13 = cos(d5); + List arrayOfDouble1 = List(3); + List arrayOfDouble2 = List(3); + arrayOfDouble1[0] = (d9 * d8); + arrayOfDouble1[1] = (d9 * d6); + arrayOfDouble1[2] = d7; + arrayOfDouble2[0] = (d13 * d12); + arrayOfDouble2[1] = (d13 * d10); + arrayOfDouble2[2] = d11; + double d14 = sqrt((arrayOfDouble1[0] - arrayOfDouble2[0]) * + (arrayOfDouble1[0] - arrayOfDouble2[0]) + + (arrayOfDouble1[1] - arrayOfDouble2[1]) * + (arrayOfDouble1[1] - arrayOfDouble2[1]) + + (arrayOfDouble1[2] - arrayOfDouble2[2]) * + (arrayOfDouble1[2] - arrayOfDouble2[2])); + print((asin(d14 / 2.0) * 12742001.579854401)); + return (asin(d14 / 2.0) * 12742001.579854401).abs(); + } else { + return 0.0; + } + } +} + +/// 获取随机坐标 +mixin NextLatLng { + final random = Random(); + + LatLng getNextLatLng({LatLng center}) { + center ??= LatLng(39.90960, 116.397228); + return LatLng( + center.latitude + random.nextDouble(), + center.longitude + random.nextDouble(), + ); + } + + List getNextBatchLatLng(int count) { + return [ + for (int i = 0; i < count; i++) + LatLng( + 39.90960 + random.nextDouble() * 4, + 116.397228 + random.nextDouble() * 4, + ) + ]; + } +} diff --git a/lib/utils/navigator_util.dart b/lib/utils/navigator_util.dart new file mode 100644 index 0000000..00c6bc1 --- /dev/null +++ b/lib/utils/navigator_util.dart @@ -0,0 +1,52 @@ +import 'package:base_app/ui/pages/user/user_login_page.dart'; +import 'package:base_app/ui/widgets/common/web_scaffold.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class NavigatorUtil { + // 打开页面 + static void pushPage( + BuildContext context, + Widget page, { + String pageName, + bool needLogin = false, + }) async { + if (context == null || page == null) return; + bool isLogin = await LoginUtils.isLogin(); + if (needLogin && isLogin == false) { + pushPage(context, UserLoginPage()); + return; + } + Navigator.push( + context, new CupertinoPageRoute(builder: (ctx) => page)); + } + + // 打开网页 + static void pushWeb(BuildContext context, + {String title, String titleId, String url}) { + if (context == null || ObjectUtil.isEmpty(url)) return; + if (url.endsWith(".apk")) { + launchInBrowser(url, title: title ?? titleId); + } else { + Navigator.push( + context, + new CupertinoPageRoute( + builder: (ctx) => new WebScaffold( + title: title, + titleId: titleId, + url: url, + ))); + } + } + + // 打开浏览器 + static Future launchInBrowser(String url, {String title}) async { + if (await canLaunch(url)) { + await launch(url, forceSafariVC: false, forceWebView: false); + } else { + throw 'Could not launch $url'; + } + } +} diff --git a/lib/utils/permission_util.dart b/lib/utils/permission_util.dart new file mode 100644 index 0000000..6e75801 --- /dev/null +++ b/lib/utils/permission_util.dart @@ -0,0 +1,15 @@ +import 'package:oktoast/oktoast.dart'; +import 'package:permission_handler/permission_handler.dart'; + +/// 请求权限工具 + +/// 请求位置权限 +Future reqPositionPermission() async { + final status = await Permission.location.request(); + if (status == PermissionStatus.granted) { + return true; + } else { + showToast('需要定位权限,请去设置中开启'); + return false; + } +} diff --git a/lib/utils/route_util.dart b/lib/utils/route_util.dart new file mode 100644 index 0000000..3d8a6a6 --- /dev/null +++ b/lib/utils/route_util.dart @@ -0,0 +1,22 @@ +import 'package:base_app/common/common.dart'; +import 'package:flutter/material.dart'; + +class RouteUtil { + // 去主页 + static void goMain(BuildContext context) { + pushReplacementNamed(context, BaseConstant.routeMain); + } + + // 去登录页 + static void goLogin(BuildContext context) { + pushReplacementNamed(context, BaseConstant.routeLogin); + } + + static void pushNamed(BuildContext context, String pageName) { + Navigator.of(context).pushNamed(pageName); + } + + static void pushReplacementNamed(BuildContext context, String pageName) { + Navigator.of(context).pushReplacementNamed(pageName); + } +} diff --git a/lib/utils/util_index.dart b/lib/utils/util_index.dart new file mode 100644 index 0000000..b240611 --- /dev/null +++ b/lib/utils/util_index.dart @@ -0,0 +1,9 @@ +export 'navigator_util.dart'; +export 'login_utils.dart'; +export 'http_utils.dart'; +export 'encrypt_helper.dart'; +export 'map_utils.dart'; +export 'navigator_util.dart'; +export 'route_util.dart'; +export 'utils.dart'; +export 'permission_util.dart'; diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart new file mode 100644 index 0000000..f2f8f38 --- /dev/null +++ b/lib/utils/utils.dart @@ -0,0 +1,152 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; +import 'dart:convert' as convert; + +/// 工具类 +class Utils { + // 是否需要登录 + static bool isNeedLogin(String pageId) { + return false; + } + + /// 显示提示信息,在屏幕下方 + static void showSnackBar(BuildContext context, String msg) { + Scaffold.of(context).showSnackBar( + SnackBar(content: Text("$msg")), + ); + } + + // 加载文本资源 + Future loadAsset(String filename) async { + return await rootBundle.loadString('assets/data/$filename'); + } + + /// 获取图片路径 + /// [name] 图片名称 不含后缀,assets/images文件夹下地图图片 + /// [format] 图片格式(后缀,如png,jpg等) + static String getImgPath(String name, {String format: 'png'}) { + return 'assets/images/$name.$format'; + } + + /// 获取文件名称 + /// [urlPath] 文件路径 + static String getFileName(String urlPath) { + if (ObjectUtil.isEmpty(urlPath)) return ''; + List listStr = urlPath.split("/"); + String name = listStr[listStr.length - 1]; + return name; + } + + /// 获取字符串对应拼音的首字母的大写字母 + /// [str] 待处理字符串 + static String getPinyin(String str) { + return PinyinHelper.getShortPinyin(str).substring(0, 1).toUpperCase(); + } + + /// 获取圆圈的背景 + static Color getCircleBg(String str) { + String pinyin = getPinyin(str); + return getCircleAvatarBg(pinyin); + } + + /// 获取头像背景颜色 + /// [key] 对照表中的key + static Color getCircleAvatarBg(String key) { + return circleAvatarMap[key]; + } + + static Color getChipBgColor(String name) { + String pinyin = PinyinHelper.getFirstWordPinyin(name); + pinyin = pinyin.substring(0, 1).toUpperCase(); + return nameToColor(pinyin); + } + + static Color nameToColor(String name) { + // assert(name.length > 1); + final int hash = name.hashCode & 0xffff; + final double hue = (360.0 * hash / (1 << 15)) % 360.0; + return HSVColor.fromAHSV(1.0, hue, 0.4, 0.90).toColor(); + } + + static String getTimeLine(BuildContext context, int timeMillis) { +// LogUtil.e("countryCode: " + +// Localizations.localeOf(context).countryCode + +// " languageCode: " + +// Localizations.localeOf(context).languageCode); + return TimelineUtil.format(timeMillis, + locale: Localizations.localeOf(context).languageCode, + dayFormat: DayFormat.Common); + } + + /// 计算标题字号 + /// [title] 标题 + static double getTitleFontSize(String title) { + // 小于10个字,18号字体 + if (ObjectUtil.isEmpty(title) || title.length < 10) { + return 18.0; + } + int count = 0; + List list = title.split(""); + for (int i = 0, length = list.length; i < length; i++) { + String ss = list[i]; + if (RegexUtil.isZh(ss)) { + count++; + } + } + //10个汉字或16个字符以上,14号字 + return (count >= 10 || title.length > 16) ? 14.0 : 18.0; + } + + /// 判断升级状态,如果远程版本小于等于当前按本,返回0 不升级, + /// 如果返回 1 升级 + /// > x 强升 + static int getUpdateStatus(String version, {String local}) { + if (ObjectUtil.isEmpty(version)) return 0; + String locVersion = local ?? AppConfig.version; + int remote = int.tryParse(version.replaceAll('.', '')); + int loc = int.tryParse(locVersion.replaceAll('.', '')); + if (remote <= loc) { + return 0; + } else { + return remote - loc; + } + } + + /// 获取加载状态 + static int getLoadStatus(bool hasError, List data) { + if (hasError) return LoadStatus.fail; + if (data == null) { + // data为空,加载中 + return LoadStatus.loading; + } else if (data.isEmpty) { + // data为空数组,返回空 + return LoadStatus.empty; + } else { + // + return LoadStatus.success; + } + } + + /// 字符串转列表 + /// [str] 待转字符串 如:[1,2,3,4,5] + static List strToList(String str) { + if (str == '') { + str = "[]"; + } + List list = convert.jsonDecode(str); + print(list); + return list; + } + + /// 列表转字符串 + /// [list] 待转列表 + static String listToStr(List list) { + String str = convert.jsonEncode(list); + print(str); + return str; + } +} diff --git a/lib/utils/version_util.dart b/lib/utils/version_util.dart new file mode 100644 index 0000000..1b92ecc --- /dev/null +++ b/lib/utils/version_util.dart @@ -0,0 +1,98 @@ +import 'dart:io'; + +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; +import 'package:install_apk_plugin/install_apk_plugin.dart'; + +import 'utils.dart'; + +/// 版本更新工具类 +class VersionUtil { + static final VersionUtil _singleton = VersionUtil._init(); + + static Dio _dio = Dio(); + + List listeners = List(); + + bool isDownload = false; + + factory VersionUtil() { + return _singleton; + } + + VersionUtil._init(); + + void downloadApk(String urlPath, String appId) async { + if (isDownload == true || ObjectUtil.isEmpty(urlPath)) return; + try { + await DirectoryUtil.getInstance(); + String apkDirPath = DirectoryUtil.getStoragePath(category: 'Download'); + LogUtil.e("apkDirPath: $apkDirPath"); + Directory apkDir = DirectoryUtil.createDirSync(apkDirPath); + + String apkName = Utils.getFileName(urlPath); + String apkPath = '$apkDirPath/$apkName'; + String apkTempPath = '$apkDirPath/temp_$apkName'; + + LogUtil.e("apkPath: $apkPath"); + LogUtil.e("apkTempPath: $apkTempPath"); + + File file = File(apkPath); + if (file.existsSync()) { + _install(apkPath, appId); + isDownload = false; + listeners.forEach((listener) { + listener(1, 1); + }); + return; + } + isDownload = true; + Response response = await _dio.download( + urlPath, + apkTempPath, + onProgress: (int count, int total) { + LogUtil.e( + "onReceiveProgress total: $total, count: $count, prect: ${count / total}"); + listeners.forEach((listener) { + listener(count, total); + }); + if (count == total) { + isDownload = false; + File file = File(apkTempPath); + File fileNew = file.copySync(apkPath); + file.deleteSync(); + _install(apkPath, appId); + } + }, + ); + } catch (e) { + LogUtil.e("download apk error: ${e?.toString()}"); + isDownload = false; + listeners.forEach((listener) { + listener(-1, 1); + }); + } + } + + void _install(String filePath, String appId) { + InstallPlugin.installApk(filePath, appId).then((result) { + LogUtil.e('install apk $result'); + }).catchError((error) { + LogUtil.e('install apk error: $error'); + }); + } + + void addListener(OnDownloadProgress listener) { + if (listener == null) return; + if (!listeners.contains(listener)) { + listeners.add(listener); + } + } + + void removeListener(OnDownloadProgress listener) { + if (listener == null) return; + if (listeners.contains(listener)) { + listeners.remove(listener); + } + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/route/fadeRoute.dart b/lib/ui/widgets/common/route/fadeRoute.dart new file mode 100644 index 0000000..09cda1e --- /dev/null +++ b/lib/ui/widgets/common/route/fadeRoute.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; + +///FadeRoute是自定义的切换过度动画(渐隐渐现) +class FadeRoute extends PageRouteBuilder { + final Widget page; + FadeRoute({this.page}): super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) =>page,transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) =>FadeTransition( + opacity: animation, + child: child, + ), + ); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/route/popRoute.dart b/lib/ui/widgets/common/route/popRoute.dart new file mode 100644 index 0000000..e779cd1 --- /dev/null +++ b/lib/ui/widgets/common/route/popRoute.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class PopRoute extends PopupRoute{ + final Duration _duration = Duration(milliseconds: 300); + Widget child; + + PopRoute({@required this.child}); + + @override + Color get barrierColor => null; + + @override + bool get barrierDismissible => true; + + @override + String get barrierLabel => null; + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + return child; + } + + @override + Duration get transitionDuration => _duration; + +} \ No newline at end of file diff --git a/lib/ui/widgets/common/web_scaffold.dart b/lib/ui/widgets/common/web_scaffold.dart new file mode 100644 index 0000000..3c7efe2 --- /dev/null +++ b/lib/ui/widgets/common/web_scaffold.dart @@ -0,0 +1,173 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; +import 'package:share/share.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +import 'button/likebtn/like_button.dart'; + +class WebScaffold extends StatefulWidget { + const WebScaffold({ + Key key, + this.title, + this.titleId, + this.url, + }) : super(key: key); + + final String title; + final String titleId; + final String url; + + @override + State createState() { + return new WebScaffoldState(); + } +} + +class WebScaffoldState extends State { +// WebViewController _webViewController; +// bool _isShowFloatBtn = false; + + void _onPopSelected(String value) { + String _title = widget.title ?? IntlUtil.getString(context, widget.titleId); + switch (value) { + case "browser": // 浏览 + NavigatorUtil.launchInBrowser(widget.url, title: _title); + break; + case "collection": // 收藏 + break; + case "share": // 分享 + String _url = widget.url; + Share.share('$_title : $_url'); + break; + default: + break; + } + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + centerTitle: true, + actions: [ + LikeButton( + width: 56.0, + duration: Duration(milliseconds: 500), + ), +// new IconButton(icon: new Icon(Icons.more_vert), onPressed: () {}), + new PopupMenuButton( + padding: const EdgeInsets.all(0.0), + onSelected: _onPopSelected, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: "browser", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '浏览器打开', + style: TextStyles.listContent, + ) + ], + ), + ))), +// new PopupMenuItem( +// value: "collection", +// child: ListTile( +// contentPadding: EdgeInsets.all(0.0), +// dense: false, +// title: new Container( +// alignment: Alignment.center, +// child: new Row( +// children: [ +// Icon( +// Icons.collections, +// color: Colours.gray_66, +// size: 22.0, +// ), +// Gaps.hGap10, +// Text( +// '收藏', +// style: TextStyles.listContent, +// ) +// ], +// ), +// ))), + new PopupMenuItem( + value: "share", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.share, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '分享', + style: TextStyles.listContent, + ) + ], + ), + ))), + ]) + ], + ), + body: new WebView( + onWebViewCreated: (WebViewController webViewController) { +// _webViewController = webViewController; +// _webViewController.addListener(() { +// int _scrollY = _webViewController.scrollY.toInt(); +// if (_scrollY < 480 && _isShowFloatBtn) { +// _isShowFloatBtn = false; +// setState(() {}); +// } else if (_scrollY > 480 && !_isShowFloatBtn) { +// _isShowFloatBtn = true; +// setState(() {}); +// } +// }); + }, + initialUrl: widget.url, + javascriptMode: JavascriptMode.unrestricted, + ), +// floatingActionButton: _buildFloatingActionButton(), + ); + } + +// Widget _buildFloatingActionButton() { +// if (_webViewController == null || _webViewController.scrollY < 480) { +// return null; +// } +// return new FloatingActionButton( +// heroTag: widget.title ?? widget.titleId, +// backgroundColor: Theme.of(context).primaryColor, +// child: Icon( +// Icons.keyboard_arrow_up, +// ), +// onPressed: () { +// _webViewController.scrollTop(); +// }); +// } +} diff --git a/lib/ui/widgets/login_page/login_item_widget.dart b/lib/ui/widgets/login_page/login_item_widget.dart new file mode 100644 index 0000000..58a8778 --- /dev/null +++ b/lib/ui/widgets/login_page/login_item_widget.dart @@ -0,0 +1,96 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 登录项 +class LoginItem extends StatefulWidget { + final IconData prefixIcon; // 前方icon + final bool hasSuffixIcon; // 是否要后面的icon + final String hintText; // 提示文字 + final bool autoFocus; // 自动聚焦 + final TextInputType keyboardType; // 键盘类型 + final int maxLength; // 最大程度 + final bool maxLengthEnforced; // 当长度达到限制长度时,是否强制组织输入 + final TextInputAction textInputAction; // 输入action + final TextEditingController controller; // controller + final FocusNode focusNode; //focusNode + final VoidCallback onEditingComplete; // 输入完毕后的回调 + + const LoginItem( + {Key key, + this.prefixIcon, + this.hasSuffixIcon = false, + this.autoFocus = false, + this.keyboardType = TextInputType.text, + this.hintText, + this.maxLength, + this.maxLengthEnforced = true, + this.textInputAction, + this.controller, + this.focusNode, + this.onEditingComplete}) + : super(key: key); + + @override + State createState() { + return LoginItemState(); + } +} + +class LoginItemState extends State { + bool _obscureText; // 是否隐藏原始文字 // 密码用 + + @override + void initState() { + super.initState(); + _obscureText = widget.hasSuffixIcon; + } + + @override + Widget build(BuildContext context) { + return new Row( + children: [ + new IconButton( + iconSize: 28, + icon: new Icon( + widget.prefixIcon, + color: Theme.of(context).primaryColor, + ), + onPressed: () {}), + Gaps.hGap5, + new Expanded( + child: new TextField( + textInputAction: widget.textInputAction, + focusNode: widget.focusNode, + onEditingComplete: widget.onEditingComplete, + obscureText: _obscureText, + controller: widget.controller, + maxLength: widget.maxLength, + maxLengthEnforced: widget.maxLengthEnforced, + style: new TextStyle(color: Colours.gray_66, fontSize: 14), + decoration: new InputDecoration( + hintText: widget.hintText, + hintStyle: new TextStyle(color: Colours.gray_99, fontSize: 14), + suffixIcon: widget.hasSuffixIcon + ? new IconButton( + icon: new Icon( + _obscureText + ? Icons.visibility + : Icons.visibility_off, + color: Colours.gray_66, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }) + : null, + focusedBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + enabledBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + )), + ), + ], + ); + } +} diff --git a/lib/utils/encrypt_helper.dart b/lib/utils/encrypt_helper.dart new file mode 100644 index 0000000..caf7196 --- /dev/null +++ b/lib/utils/encrypt_helper.dart @@ -0,0 +1,30 @@ +import 'package:encrypt/encrypt.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +import 'dart:async'; +import 'package:flutter/services.dart' show rootBundle; + +/// RSA加密工具 +final parser = RSAKeyParser(); + +class EncryptHelper { + /// 加密 + ///[src] 待加密字符串 + static Future encode(String src) async { + String publicKeyString = await rootBundle.loadString('keys/public_key.pem'); + RSAPublicKey publicKey = parser.parse(publicKeyString); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + return encrypter.encrypt(src).base64; + } + + /// 解密 + /// [decoded] 待解密字符串 + static Future decode(String decoded) async { + String privateKeyString = + await rootBundle.loadString('keys/private_key.pem'); + + final privateKey = parser.parse(privateKeyString); + + final encrypter = Encrypter(RSA(privateKey: privateKey)); + return encrypter.decrypt(Encrypted.fromBase64(decoded)); + } +} diff --git a/lib/utils/http_utils.dart b/lib/utils/http_utils.dart new file mode 100644 index 0000000..319ca63 --- /dev/null +++ b/lib/utils/http_utils.dart @@ -0,0 +1,30 @@ +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/models/common/version_model.dart'; + +/// 模拟网络请求数据 +class HttpUtils { + Future getSplash() { + return Future.delayed(Duration(milliseconds: 500), () { + return SplashModel( + title: 'Flutter 常用工具类库', + content: 'Flutter 常用工具类库', + url: 'https://www.jianshu.com/p/425a7ff9d66e', + imgUrl: + 'https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_common_utils_a.png', + ); + }); + } + + /// 该地址可能无法下载,请自行更换可测试apk地址。 + Future getVersion() async { + return Future.delayed(Duration(milliseconds: 500), () { + return VersionModel( + title: '有新版本v1.1.0,快去更新吧!', + content: '1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~', + url: + 'https://raw.githubusercontent.com/Sky24n/Doc/master/apks/flutter_wanandroid.apk', + version: '1.0.0', + ); + }); + } +} diff --git a/lib/utils/login_utils.dart b/lib/utils/login_utils.dart new file mode 100644 index 0000000..af31546 --- /dev/null +++ b/lib/utils/login_utils.dart @@ -0,0 +1,47 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flustars/flustars.dart'; + +/// 登录工具类 +class LoginUtils { + /// 判断用户是否已登录 + static Future isLogin() async { + // 1. 先判断token是否在 + bool hasToken = + ObjectUtil.isNotEmpty(SpUtil.getString(BaseConstant.keyAppToken)); + if (hasToken) { + // 2.用token去获取用户信息,有信息认为已登录,否则为未登录 + UserRepository userRepository = new UserRepository(); + UserModel user = await userRepository.getUserInfo(); + if (user == null) { + // 未登录的尝试自动登录,返回自动登录结果 + return await autoLogin(); + } else { + return true; + } + } else { + return hasToken; + } + } + + // 自动登录 + static Future autoLogin() async { + // 取用户名和密码自动登录 + String username = SpUtil.getString(BaseConstant.keyAccount); + String password = SpUtil.getString(BaseConstant.keyPassword); + UserRepository userRepository = new UserRepository(); + LoginReq req = new LoginReq(username, password); + try { + UserModel model = await userRepository.login(req); + if (model != null) { + return true; + } else { + return false; + } + } catch (error) { + return false; + } + } +} diff --git a/lib/utils/map_utils.dart b/lib/utils/map_utils.dart new file mode 100644 index 0000000..dc6029d --- /dev/null +++ b/lib/utils/map_utils.dart @@ -0,0 +1,72 @@ +import 'dart:math'; + +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; + +/// 地图工具类 +class MapUtils { + ///计算两点距离 + ///[start] 第一个点坐标[lng,lat] + ///[end]第二个点坐标[lng,lat] + static double calculateDistance(start, end) { + if ((start != null) || (end != null)) { + double d1 = 0.01745329251994329; + double d2 = start[0]; //lng + double d3 = start[1]; //lat + double d4 = end[0]; //lng + double d5 = end[1]; //lat + d2 *= d1; + d3 *= d1; + d4 *= d1; + d5 *= d1; + double d6 = sin(d2); + double d7 = sin(d3); + double d8 = cos(d2); + double d9 = cos(d3); + double d10 = sin(d4); + double d11 = sin(d5); + double d12 = cos(d4); + double d13 = cos(d5); + List arrayOfDouble1 = List(3); + List arrayOfDouble2 = List(3); + arrayOfDouble1[0] = (d9 * d8); + arrayOfDouble1[1] = (d9 * d6); + arrayOfDouble1[2] = d7; + arrayOfDouble2[0] = (d13 * d12); + arrayOfDouble2[1] = (d13 * d10); + arrayOfDouble2[2] = d11; + double d14 = sqrt((arrayOfDouble1[0] - arrayOfDouble2[0]) * + (arrayOfDouble1[0] - arrayOfDouble2[0]) + + (arrayOfDouble1[1] - arrayOfDouble2[1]) * + (arrayOfDouble1[1] - arrayOfDouble2[1]) + + (arrayOfDouble1[2] - arrayOfDouble2[2]) * + (arrayOfDouble1[2] - arrayOfDouble2[2])); + print((asin(d14 / 2.0) * 12742001.579854401)); + return (asin(d14 / 2.0) * 12742001.579854401).abs(); + } else { + return 0.0; + } + } +} + +/// 获取随机坐标 +mixin NextLatLng { + final random = Random(); + + LatLng getNextLatLng({LatLng center}) { + center ??= LatLng(39.90960, 116.397228); + return LatLng( + center.latitude + random.nextDouble(), + center.longitude + random.nextDouble(), + ); + } + + List getNextBatchLatLng(int count) { + return [ + for (int i = 0; i < count; i++) + LatLng( + 39.90960 + random.nextDouble() * 4, + 116.397228 + random.nextDouble() * 4, + ) + ]; + } +} diff --git a/lib/utils/navigator_util.dart b/lib/utils/navigator_util.dart new file mode 100644 index 0000000..00c6bc1 --- /dev/null +++ b/lib/utils/navigator_util.dart @@ -0,0 +1,52 @@ +import 'package:base_app/ui/pages/user/user_login_page.dart'; +import 'package:base_app/ui/widgets/common/web_scaffold.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class NavigatorUtil { + // 打开页面 + static void pushPage( + BuildContext context, + Widget page, { + String pageName, + bool needLogin = false, + }) async { + if (context == null || page == null) return; + bool isLogin = await LoginUtils.isLogin(); + if (needLogin && isLogin == false) { + pushPage(context, UserLoginPage()); + return; + } + Navigator.push( + context, new CupertinoPageRoute(builder: (ctx) => page)); + } + + // 打开网页 + static void pushWeb(BuildContext context, + {String title, String titleId, String url}) { + if (context == null || ObjectUtil.isEmpty(url)) return; + if (url.endsWith(".apk")) { + launchInBrowser(url, title: title ?? titleId); + } else { + Navigator.push( + context, + new CupertinoPageRoute( + builder: (ctx) => new WebScaffold( + title: title, + titleId: titleId, + url: url, + ))); + } + } + + // 打开浏览器 + static Future launchInBrowser(String url, {String title}) async { + if (await canLaunch(url)) { + await launch(url, forceSafariVC: false, forceWebView: false); + } else { + throw 'Could not launch $url'; + } + } +} diff --git a/lib/utils/permission_util.dart b/lib/utils/permission_util.dart new file mode 100644 index 0000000..6e75801 --- /dev/null +++ b/lib/utils/permission_util.dart @@ -0,0 +1,15 @@ +import 'package:oktoast/oktoast.dart'; +import 'package:permission_handler/permission_handler.dart'; + +/// 请求权限工具 + +/// 请求位置权限 +Future reqPositionPermission() async { + final status = await Permission.location.request(); + if (status == PermissionStatus.granted) { + return true; + } else { + showToast('需要定位权限,请去设置中开启'); + return false; + } +} diff --git a/lib/utils/route_util.dart b/lib/utils/route_util.dart new file mode 100644 index 0000000..3d8a6a6 --- /dev/null +++ b/lib/utils/route_util.dart @@ -0,0 +1,22 @@ +import 'package:base_app/common/common.dart'; +import 'package:flutter/material.dart'; + +class RouteUtil { + // 去主页 + static void goMain(BuildContext context) { + pushReplacementNamed(context, BaseConstant.routeMain); + } + + // 去登录页 + static void goLogin(BuildContext context) { + pushReplacementNamed(context, BaseConstant.routeLogin); + } + + static void pushNamed(BuildContext context, String pageName) { + Navigator.of(context).pushNamed(pageName); + } + + static void pushReplacementNamed(BuildContext context, String pageName) { + Navigator.of(context).pushReplacementNamed(pageName); + } +} diff --git a/lib/utils/util_index.dart b/lib/utils/util_index.dart new file mode 100644 index 0000000..b240611 --- /dev/null +++ b/lib/utils/util_index.dart @@ -0,0 +1,9 @@ +export 'navigator_util.dart'; +export 'login_utils.dart'; +export 'http_utils.dart'; +export 'encrypt_helper.dart'; +export 'map_utils.dart'; +export 'navigator_util.dart'; +export 'route_util.dart'; +export 'utils.dart'; +export 'permission_util.dart'; diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart new file mode 100644 index 0000000..f2f8f38 --- /dev/null +++ b/lib/utils/utils.dart @@ -0,0 +1,152 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; +import 'dart:convert' as convert; + +/// 工具类 +class Utils { + // 是否需要登录 + static bool isNeedLogin(String pageId) { + return false; + } + + /// 显示提示信息,在屏幕下方 + static void showSnackBar(BuildContext context, String msg) { + Scaffold.of(context).showSnackBar( + SnackBar(content: Text("$msg")), + ); + } + + // 加载文本资源 + Future loadAsset(String filename) async { + return await rootBundle.loadString('assets/data/$filename'); + } + + /// 获取图片路径 + /// [name] 图片名称 不含后缀,assets/images文件夹下地图图片 + /// [format] 图片格式(后缀,如png,jpg等) + static String getImgPath(String name, {String format: 'png'}) { + return 'assets/images/$name.$format'; + } + + /// 获取文件名称 + /// [urlPath] 文件路径 + static String getFileName(String urlPath) { + if (ObjectUtil.isEmpty(urlPath)) return ''; + List listStr = urlPath.split("/"); + String name = listStr[listStr.length - 1]; + return name; + } + + /// 获取字符串对应拼音的首字母的大写字母 + /// [str] 待处理字符串 + static String getPinyin(String str) { + return PinyinHelper.getShortPinyin(str).substring(0, 1).toUpperCase(); + } + + /// 获取圆圈的背景 + static Color getCircleBg(String str) { + String pinyin = getPinyin(str); + return getCircleAvatarBg(pinyin); + } + + /// 获取头像背景颜色 + /// [key] 对照表中的key + static Color getCircleAvatarBg(String key) { + return circleAvatarMap[key]; + } + + static Color getChipBgColor(String name) { + String pinyin = PinyinHelper.getFirstWordPinyin(name); + pinyin = pinyin.substring(0, 1).toUpperCase(); + return nameToColor(pinyin); + } + + static Color nameToColor(String name) { + // assert(name.length > 1); + final int hash = name.hashCode & 0xffff; + final double hue = (360.0 * hash / (1 << 15)) % 360.0; + return HSVColor.fromAHSV(1.0, hue, 0.4, 0.90).toColor(); + } + + static String getTimeLine(BuildContext context, int timeMillis) { +// LogUtil.e("countryCode: " + +// Localizations.localeOf(context).countryCode + +// " languageCode: " + +// Localizations.localeOf(context).languageCode); + return TimelineUtil.format(timeMillis, + locale: Localizations.localeOf(context).languageCode, + dayFormat: DayFormat.Common); + } + + /// 计算标题字号 + /// [title] 标题 + static double getTitleFontSize(String title) { + // 小于10个字,18号字体 + if (ObjectUtil.isEmpty(title) || title.length < 10) { + return 18.0; + } + int count = 0; + List list = title.split(""); + for (int i = 0, length = list.length; i < length; i++) { + String ss = list[i]; + if (RegexUtil.isZh(ss)) { + count++; + } + } + //10个汉字或16个字符以上,14号字 + return (count >= 10 || title.length > 16) ? 14.0 : 18.0; + } + + /// 判断升级状态,如果远程版本小于等于当前按本,返回0 不升级, + /// 如果返回 1 升级 + /// > x 强升 + static int getUpdateStatus(String version, {String local}) { + if (ObjectUtil.isEmpty(version)) return 0; + String locVersion = local ?? AppConfig.version; + int remote = int.tryParse(version.replaceAll('.', '')); + int loc = int.tryParse(locVersion.replaceAll('.', '')); + if (remote <= loc) { + return 0; + } else { + return remote - loc; + } + } + + /// 获取加载状态 + static int getLoadStatus(bool hasError, List data) { + if (hasError) return LoadStatus.fail; + if (data == null) { + // data为空,加载中 + return LoadStatus.loading; + } else if (data.isEmpty) { + // data为空数组,返回空 + return LoadStatus.empty; + } else { + // + return LoadStatus.success; + } + } + + /// 字符串转列表 + /// [str] 待转字符串 如:[1,2,3,4,5] + static List strToList(String str) { + if (str == '') { + str = "[]"; + } + List list = convert.jsonDecode(str); + print(list); + return list; + } + + /// 列表转字符串 + /// [list] 待转列表 + static String listToStr(List list) { + String str = convert.jsonEncode(list); + print(str); + return str; + } +} diff --git a/lib/utils/version_util.dart b/lib/utils/version_util.dart new file mode 100644 index 0000000..1b92ecc --- /dev/null +++ b/lib/utils/version_util.dart @@ -0,0 +1,98 @@ +import 'dart:io'; + +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; +import 'package:install_apk_plugin/install_apk_plugin.dart'; + +import 'utils.dart'; + +/// 版本更新工具类 +class VersionUtil { + static final VersionUtil _singleton = VersionUtil._init(); + + static Dio _dio = Dio(); + + List listeners = List(); + + bool isDownload = false; + + factory VersionUtil() { + return _singleton; + } + + VersionUtil._init(); + + void downloadApk(String urlPath, String appId) async { + if (isDownload == true || ObjectUtil.isEmpty(urlPath)) return; + try { + await DirectoryUtil.getInstance(); + String apkDirPath = DirectoryUtil.getStoragePath(category: 'Download'); + LogUtil.e("apkDirPath: $apkDirPath"); + Directory apkDir = DirectoryUtil.createDirSync(apkDirPath); + + String apkName = Utils.getFileName(urlPath); + String apkPath = '$apkDirPath/$apkName'; + String apkTempPath = '$apkDirPath/temp_$apkName'; + + LogUtil.e("apkPath: $apkPath"); + LogUtil.e("apkTempPath: $apkTempPath"); + + File file = File(apkPath); + if (file.existsSync()) { + _install(apkPath, appId); + isDownload = false; + listeners.forEach((listener) { + listener(1, 1); + }); + return; + } + isDownload = true; + Response response = await _dio.download( + urlPath, + apkTempPath, + onProgress: (int count, int total) { + LogUtil.e( + "onReceiveProgress total: $total, count: $count, prect: ${count / total}"); + listeners.forEach((listener) { + listener(count, total); + }); + if (count == total) { + isDownload = false; + File file = File(apkTempPath); + File fileNew = file.copySync(apkPath); + file.deleteSync(); + _install(apkPath, appId); + } + }, + ); + } catch (e) { + LogUtil.e("download apk error: ${e?.toString()}"); + isDownload = false; + listeners.forEach((listener) { + listener(-1, 1); + }); + } + } + + void _install(String filePath, String appId) { + InstallPlugin.installApk(filePath, appId).then((result) { + LogUtil.e('install apk $result'); + }).catchError((error) { + LogUtil.e('install apk error: $error'); + }); + } + + void addListener(OnDownloadProgress listener) { + if (listener == null) return; + if (!listeners.contains(listener)) { + listeners.add(listener); + } + } + + void removeListener(OnDownloadProgress listener) { + if (listener == null) return; + if (listeners.contains(listener)) { + listeners.remove(listener); + } + } +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..74cac3b --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,640 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + amap_core_fluttify: + dependency: transitive + description: + name: amap_core_fluttify + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.9.5" + amap_map_fluttify: + dependency: "direct main" + description: + name: amap_map_fluttify + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.24.0+3" + archive: + dependency: transitive + description: + name: archive + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.13" + args: + dependency: transitive + description: + name: args + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.6.0" + asn1lib: + dependency: transitive + description: + name: asn1lib + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.5" + async: + dependency: transitive + description: + name: async + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.1" + azlistview: + dependency: "direct main" + description: + name: azlistview + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.2" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.3" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.14.12" + common_utils: + dependency: transitive + description: + name: common_utils + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.1" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.1" + cookie_jar: + dependency: transitive + description: + name: cookie_jar + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.8" + core_location_fluttify: + dependency: transitive + description: + name: core_location_fluttify + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.4" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.4" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.3" + decimal: + dependency: transitive + description: + name: decimal + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.5" + dio: + dependency: "direct main" + description: + name: dio + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.13" + encrypt: + dependency: "direct main" + description: + name: encrypt + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.0.2" + file: + dependency: transitive + description: + name: file + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.2.1" + fluintl: + dependency: "direct main" + description: + name: fluintl + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.3" + flukit: + dependency: "direct main" + description: + name: flukit + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + flustars: + dependency: "direct main" + description: + name: flustars + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.3" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.3" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.8" + 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" + foundation_fluttify: + dependency: transitive + description: + name: foundation_fluttify + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.8.11" + http: + dependency: transitive + description: + name: http + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.12.2" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.1.4" + image: + dependency: transitive + description: + name: image + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.12" + image_picker: + dependency: "direct main" + description: + name: image_picker + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.7+4" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + install_apk_plugin: + dependency: "direct main" + description: + name: install_apk_plugin + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" + intl: + dependency: transitive + description: + name: intl + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.16.1" + latlng: + dependency: transitive + description: + name: latlng + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.2" + lpinyin: + dependency: "direct main" + description: + name: lpinyin + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.9" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.12.6" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.8" + oktoast: + dependency: "direct main" + description: + name: oktoast + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.3.2" + path: + dependency: transitive + description: + name: path + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.6.4" + path_provider: + dependency: transitive + description: + name: path_provider + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.6.11" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1+2" + path_provider_macos: + dependency: transitive + description: + name: path_provider_macos + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.4+3" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + pedantic: + dependency: transitive + description: + name: pedantic + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.9.0" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.0.1+1" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.1" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.0" + photo_view: + dependency: "direct main" + description: + name: photo_view + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.9.2" + platform: + dependency: transitive + description: + name: platform + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.1" + platform_detect: + dependency: transitive + description: + name: platform_detect + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.4.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + pointycastle: + dependency: transitive + description: + name: pointycastle + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + process: + dependency: transitive + description: + name: process + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.13" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.4.4" + pull_to_refresh: + dependency: "direct main" + description: + name: pull_to_refresh + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.6" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.3" + rational: + dependency: transitive + description: + name: rational + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.8" + rxdart: + dependency: "direct main" + description: + name: rxdart + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.22.6" + share: + dependency: "direct main" + description: + name: share + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.4+3" + shared_preferences: + dependency: transitive + description: + name: shared_preferences + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.5.8" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.2+1" + shared_preferences_macos: + dependency: transitive + description: + name: shared_preferences_macos + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1+10" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.4" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.2+7" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.7.0" + sp_util: + dependency: transitive + description: + name: sp_util + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" + sqflite: + dependency: "direct main" + description: + name: sqflite + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.1" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2+1" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.9.3" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.5" + synchronized: + dependency: transitive + description: + name: synchronized + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.0+2" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.15" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.6" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.5.0" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1+1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1+7" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.7" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.2" + uuid: + dependency: transitive + description: + name: uuid + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.0" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.8" + webview_flutter: + dependency: "direct main" + description: + name: webview_flutter + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.22+1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.0" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.6.1" +sdks: + dart: ">=2.8.0 <3.0.0" + flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/route/fadeRoute.dart b/lib/ui/widgets/common/route/fadeRoute.dart new file mode 100644 index 0000000..09cda1e --- /dev/null +++ b/lib/ui/widgets/common/route/fadeRoute.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; + +///FadeRoute是自定义的切换过度动画(渐隐渐现) +class FadeRoute extends PageRouteBuilder { + final Widget page; + FadeRoute({this.page}): super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) =>page,transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) =>FadeTransition( + opacity: animation, + child: child, + ), + ); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/route/popRoute.dart b/lib/ui/widgets/common/route/popRoute.dart new file mode 100644 index 0000000..e779cd1 --- /dev/null +++ b/lib/ui/widgets/common/route/popRoute.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class PopRoute extends PopupRoute{ + final Duration _duration = Duration(milliseconds: 300); + Widget child; + + PopRoute({@required this.child}); + + @override + Color get barrierColor => null; + + @override + bool get barrierDismissible => true; + + @override + String get barrierLabel => null; + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + return child; + } + + @override + Duration get transitionDuration => _duration; + +} \ No newline at end of file diff --git a/lib/ui/widgets/common/web_scaffold.dart b/lib/ui/widgets/common/web_scaffold.dart new file mode 100644 index 0000000..3c7efe2 --- /dev/null +++ b/lib/ui/widgets/common/web_scaffold.dart @@ -0,0 +1,173 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; +import 'package:share/share.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +import 'button/likebtn/like_button.dart'; + +class WebScaffold extends StatefulWidget { + const WebScaffold({ + Key key, + this.title, + this.titleId, + this.url, + }) : super(key: key); + + final String title; + final String titleId; + final String url; + + @override + State createState() { + return new WebScaffoldState(); + } +} + +class WebScaffoldState extends State { +// WebViewController _webViewController; +// bool _isShowFloatBtn = false; + + void _onPopSelected(String value) { + String _title = widget.title ?? IntlUtil.getString(context, widget.titleId); + switch (value) { + case "browser": // 浏览 + NavigatorUtil.launchInBrowser(widget.url, title: _title); + break; + case "collection": // 收藏 + break; + case "share": // 分享 + String _url = widget.url; + Share.share('$_title : $_url'); + break; + default: + break; + } + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + centerTitle: true, + actions: [ + LikeButton( + width: 56.0, + duration: Duration(milliseconds: 500), + ), +// new IconButton(icon: new Icon(Icons.more_vert), onPressed: () {}), + new PopupMenuButton( + padding: const EdgeInsets.all(0.0), + onSelected: _onPopSelected, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: "browser", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '浏览器打开', + style: TextStyles.listContent, + ) + ], + ), + ))), +// new PopupMenuItem( +// value: "collection", +// child: ListTile( +// contentPadding: EdgeInsets.all(0.0), +// dense: false, +// title: new Container( +// alignment: Alignment.center, +// child: new Row( +// children: [ +// Icon( +// Icons.collections, +// color: Colours.gray_66, +// size: 22.0, +// ), +// Gaps.hGap10, +// Text( +// '收藏', +// style: TextStyles.listContent, +// ) +// ], +// ), +// ))), + new PopupMenuItem( + value: "share", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.share, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '分享', + style: TextStyles.listContent, + ) + ], + ), + ))), + ]) + ], + ), + body: new WebView( + onWebViewCreated: (WebViewController webViewController) { +// _webViewController = webViewController; +// _webViewController.addListener(() { +// int _scrollY = _webViewController.scrollY.toInt(); +// if (_scrollY < 480 && _isShowFloatBtn) { +// _isShowFloatBtn = false; +// setState(() {}); +// } else if (_scrollY > 480 && !_isShowFloatBtn) { +// _isShowFloatBtn = true; +// setState(() {}); +// } +// }); + }, + initialUrl: widget.url, + javascriptMode: JavascriptMode.unrestricted, + ), +// floatingActionButton: _buildFloatingActionButton(), + ); + } + +// Widget _buildFloatingActionButton() { +// if (_webViewController == null || _webViewController.scrollY < 480) { +// return null; +// } +// return new FloatingActionButton( +// heroTag: widget.title ?? widget.titleId, +// backgroundColor: Theme.of(context).primaryColor, +// child: Icon( +// Icons.keyboard_arrow_up, +// ), +// onPressed: () { +// _webViewController.scrollTop(); +// }); +// } +} diff --git a/lib/ui/widgets/login_page/login_item_widget.dart b/lib/ui/widgets/login_page/login_item_widget.dart new file mode 100644 index 0000000..58a8778 --- /dev/null +++ b/lib/ui/widgets/login_page/login_item_widget.dart @@ -0,0 +1,96 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 登录项 +class LoginItem extends StatefulWidget { + final IconData prefixIcon; // 前方icon + final bool hasSuffixIcon; // 是否要后面的icon + final String hintText; // 提示文字 + final bool autoFocus; // 自动聚焦 + final TextInputType keyboardType; // 键盘类型 + final int maxLength; // 最大程度 + final bool maxLengthEnforced; // 当长度达到限制长度时,是否强制组织输入 + final TextInputAction textInputAction; // 输入action + final TextEditingController controller; // controller + final FocusNode focusNode; //focusNode + final VoidCallback onEditingComplete; // 输入完毕后的回调 + + const LoginItem( + {Key key, + this.prefixIcon, + this.hasSuffixIcon = false, + this.autoFocus = false, + this.keyboardType = TextInputType.text, + this.hintText, + this.maxLength, + this.maxLengthEnforced = true, + this.textInputAction, + this.controller, + this.focusNode, + this.onEditingComplete}) + : super(key: key); + + @override + State createState() { + return LoginItemState(); + } +} + +class LoginItemState extends State { + bool _obscureText; // 是否隐藏原始文字 // 密码用 + + @override + void initState() { + super.initState(); + _obscureText = widget.hasSuffixIcon; + } + + @override + Widget build(BuildContext context) { + return new Row( + children: [ + new IconButton( + iconSize: 28, + icon: new Icon( + widget.prefixIcon, + color: Theme.of(context).primaryColor, + ), + onPressed: () {}), + Gaps.hGap5, + new Expanded( + child: new TextField( + textInputAction: widget.textInputAction, + focusNode: widget.focusNode, + onEditingComplete: widget.onEditingComplete, + obscureText: _obscureText, + controller: widget.controller, + maxLength: widget.maxLength, + maxLengthEnforced: widget.maxLengthEnforced, + style: new TextStyle(color: Colours.gray_66, fontSize: 14), + decoration: new InputDecoration( + hintText: widget.hintText, + hintStyle: new TextStyle(color: Colours.gray_99, fontSize: 14), + suffixIcon: widget.hasSuffixIcon + ? new IconButton( + icon: new Icon( + _obscureText + ? Icons.visibility + : Icons.visibility_off, + color: Colours.gray_66, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }) + : null, + focusedBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + enabledBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + )), + ), + ], + ); + } +} diff --git a/lib/utils/encrypt_helper.dart b/lib/utils/encrypt_helper.dart new file mode 100644 index 0000000..caf7196 --- /dev/null +++ b/lib/utils/encrypt_helper.dart @@ -0,0 +1,30 @@ +import 'package:encrypt/encrypt.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +import 'dart:async'; +import 'package:flutter/services.dart' show rootBundle; + +/// RSA加密工具 +final parser = RSAKeyParser(); + +class EncryptHelper { + /// 加密 + ///[src] 待加密字符串 + static Future encode(String src) async { + String publicKeyString = await rootBundle.loadString('keys/public_key.pem'); + RSAPublicKey publicKey = parser.parse(publicKeyString); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + return encrypter.encrypt(src).base64; + } + + /// 解密 + /// [decoded] 待解密字符串 + static Future decode(String decoded) async { + String privateKeyString = + await rootBundle.loadString('keys/private_key.pem'); + + final privateKey = parser.parse(privateKeyString); + + final encrypter = Encrypter(RSA(privateKey: privateKey)); + return encrypter.decrypt(Encrypted.fromBase64(decoded)); + } +} diff --git a/lib/utils/http_utils.dart b/lib/utils/http_utils.dart new file mode 100644 index 0000000..319ca63 --- /dev/null +++ b/lib/utils/http_utils.dart @@ -0,0 +1,30 @@ +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/models/common/version_model.dart'; + +/// 模拟网络请求数据 +class HttpUtils { + Future getSplash() { + return Future.delayed(Duration(milliseconds: 500), () { + return SplashModel( + title: 'Flutter 常用工具类库', + content: 'Flutter 常用工具类库', + url: 'https://www.jianshu.com/p/425a7ff9d66e', + imgUrl: + 'https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_common_utils_a.png', + ); + }); + } + + /// 该地址可能无法下载,请自行更换可测试apk地址。 + Future getVersion() async { + return Future.delayed(Duration(milliseconds: 500), () { + return VersionModel( + title: '有新版本v1.1.0,快去更新吧!', + content: '1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~', + url: + 'https://raw.githubusercontent.com/Sky24n/Doc/master/apks/flutter_wanandroid.apk', + version: '1.0.0', + ); + }); + } +} diff --git a/lib/utils/login_utils.dart b/lib/utils/login_utils.dart new file mode 100644 index 0000000..af31546 --- /dev/null +++ b/lib/utils/login_utils.dart @@ -0,0 +1,47 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flustars/flustars.dart'; + +/// 登录工具类 +class LoginUtils { + /// 判断用户是否已登录 + static Future isLogin() async { + // 1. 先判断token是否在 + bool hasToken = + ObjectUtil.isNotEmpty(SpUtil.getString(BaseConstant.keyAppToken)); + if (hasToken) { + // 2.用token去获取用户信息,有信息认为已登录,否则为未登录 + UserRepository userRepository = new UserRepository(); + UserModel user = await userRepository.getUserInfo(); + if (user == null) { + // 未登录的尝试自动登录,返回自动登录结果 + return await autoLogin(); + } else { + return true; + } + } else { + return hasToken; + } + } + + // 自动登录 + static Future autoLogin() async { + // 取用户名和密码自动登录 + String username = SpUtil.getString(BaseConstant.keyAccount); + String password = SpUtil.getString(BaseConstant.keyPassword); + UserRepository userRepository = new UserRepository(); + LoginReq req = new LoginReq(username, password); + try { + UserModel model = await userRepository.login(req); + if (model != null) { + return true; + } else { + return false; + } + } catch (error) { + return false; + } + } +} diff --git a/lib/utils/map_utils.dart b/lib/utils/map_utils.dart new file mode 100644 index 0000000..dc6029d --- /dev/null +++ b/lib/utils/map_utils.dart @@ -0,0 +1,72 @@ +import 'dart:math'; + +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; + +/// 地图工具类 +class MapUtils { + ///计算两点距离 + ///[start] 第一个点坐标[lng,lat] + ///[end]第二个点坐标[lng,lat] + static double calculateDistance(start, end) { + if ((start != null) || (end != null)) { + double d1 = 0.01745329251994329; + double d2 = start[0]; //lng + double d3 = start[1]; //lat + double d4 = end[0]; //lng + double d5 = end[1]; //lat + d2 *= d1; + d3 *= d1; + d4 *= d1; + d5 *= d1; + double d6 = sin(d2); + double d7 = sin(d3); + double d8 = cos(d2); + double d9 = cos(d3); + double d10 = sin(d4); + double d11 = sin(d5); + double d12 = cos(d4); + double d13 = cos(d5); + List arrayOfDouble1 = List(3); + List arrayOfDouble2 = List(3); + arrayOfDouble1[0] = (d9 * d8); + arrayOfDouble1[1] = (d9 * d6); + arrayOfDouble1[2] = d7; + arrayOfDouble2[0] = (d13 * d12); + arrayOfDouble2[1] = (d13 * d10); + arrayOfDouble2[2] = d11; + double d14 = sqrt((arrayOfDouble1[0] - arrayOfDouble2[0]) * + (arrayOfDouble1[0] - arrayOfDouble2[0]) + + (arrayOfDouble1[1] - arrayOfDouble2[1]) * + (arrayOfDouble1[1] - arrayOfDouble2[1]) + + (arrayOfDouble1[2] - arrayOfDouble2[2]) * + (arrayOfDouble1[2] - arrayOfDouble2[2])); + print((asin(d14 / 2.0) * 12742001.579854401)); + return (asin(d14 / 2.0) * 12742001.579854401).abs(); + } else { + return 0.0; + } + } +} + +/// 获取随机坐标 +mixin NextLatLng { + final random = Random(); + + LatLng getNextLatLng({LatLng center}) { + center ??= LatLng(39.90960, 116.397228); + return LatLng( + center.latitude + random.nextDouble(), + center.longitude + random.nextDouble(), + ); + } + + List getNextBatchLatLng(int count) { + return [ + for (int i = 0; i < count; i++) + LatLng( + 39.90960 + random.nextDouble() * 4, + 116.397228 + random.nextDouble() * 4, + ) + ]; + } +} diff --git a/lib/utils/navigator_util.dart b/lib/utils/navigator_util.dart new file mode 100644 index 0000000..00c6bc1 --- /dev/null +++ b/lib/utils/navigator_util.dart @@ -0,0 +1,52 @@ +import 'package:base_app/ui/pages/user/user_login_page.dart'; +import 'package:base_app/ui/widgets/common/web_scaffold.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class NavigatorUtil { + // 打开页面 + static void pushPage( + BuildContext context, + Widget page, { + String pageName, + bool needLogin = false, + }) async { + if (context == null || page == null) return; + bool isLogin = await LoginUtils.isLogin(); + if (needLogin && isLogin == false) { + pushPage(context, UserLoginPage()); + return; + } + Navigator.push( + context, new CupertinoPageRoute(builder: (ctx) => page)); + } + + // 打开网页 + static void pushWeb(BuildContext context, + {String title, String titleId, String url}) { + if (context == null || ObjectUtil.isEmpty(url)) return; + if (url.endsWith(".apk")) { + launchInBrowser(url, title: title ?? titleId); + } else { + Navigator.push( + context, + new CupertinoPageRoute( + builder: (ctx) => new WebScaffold( + title: title, + titleId: titleId, + url: url, + ))); + } + } + + // 打开浏览器 + static Future launchInBrowser(String url, {String title}) async { + if (await canLaunch(url)) { + await launch(url, forceSafariVC: false, forceWebView: false); + } else { + throw 'Could not launch $url'; + } + } +} diff --git a/lib/utils/permission_util.dart b/lib/utils/permission_util.dart new file mode 100644 index 0000000..6e75801 --- /dev/null +++ b/lib/utils/permission_util.dart @@ -0,0 +1,15 @@ +import 'package:oktoast/oktoast.dart'; +import 'package:permission_handler/permission_handler.dart'; + +/// 请求权限工具 + +/// 请求位置权限 +Future reqPositionPermission() async { + final status = await Permission.location.request(); + if (status == PermissionStatus.granted) { + return true; + } else { + showToast('需要定位权限,请去设置中开启'); + return false; + } +} diff --git a/lib/utils/route_util.dart b/lib/utils/route_util.dart new file mode 100644 index 0000000..3d8a6a6 --- /dev/null +++ b/lib/utils/route_util.dart @@ -0,0 +1,22 @@ +import 'package:base_app/common/common.dart'; +import 'package:flutter/material.dart'; + +class RouteUtil { + // 去主页 + static void goMain(BuildContext context) { + pushReplacementNamed(context, BaseConstant.routeMain); + } + + // 去登录页 + static void goLogin(BuildContext context) { + pushReplacementNamed(context, BaseConstant.routeLogin); + } + + static void pushNamed(BuildContext context, String pageName) { + Navigator.of(context).pushNamed(pageName); + } + + static void pushReplacementNamed(BuildContext context, String pageName) { + Navigator.of(context).pushReplacementNamed(pageName); + } +} diff --git a/lib/utils/util_index.dart b/lib/utils/util_index.dart new file mode 100644 index 0000000..b240611 --- /dev/null +++ b/lib/utils/util_index.dart @@ -0,0 +1,9 @@ +export 'navigator_util.dart'; +export 'login_utils.dart'; +export 'http_utils.dart'; +export 'encrypt_helper.dart'; +export 'map_utils.dart'; +export 'navigator_util.dart'; +export 'route_util.dart'; +export 'utils.dart'; +export 'permission_util.dart'; diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart new file mode 100644 index 0000000..f2f8f38 --- /dev/null +++ b/lib/utils/utils.dart @@ -0,0 +1,152 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; +import 'dart:convert' as convert; + +/// 工具类 +class Utils { + // 是否需要登录 + static bool isNeedLogin(String pageId) { + return false; + } + + /// 显示提示信息,在屏幕下方 + static void showSnackBar(BuildContext context, String msg) { + Scaffold.of(context).showSnackBar( + SnackBar(content: Text("$msg")), + ); + } + + // 加载文本资源 + Future loadAsset(String filename) async { + return await rootBundle.loadString('assets/data/$filename'); + } + + /// 获取图片路径 + /// [name] 图片名称 不含后缀,assets/images文件夹下地图图片 + /// [format] 图片格式(后缀,如png,jpg等) + static String getImgPath(String name, {String format: 'png'}) { + return 'assets/images/$name.$format'; + } + + /// 获取文件名称 + /// [urlPath] 文件路径 + static String getFileName(String urlPath) { + if (ObjectUtil.isEmpty(urlPath)) return ''; + List listStr = urlPath.split("/"); + String name = listStr[listStr.length - 1]; + return name; + } + + /// 获取字符串对应拼音的首字母的大写字母 + /// [str] 待处理字符串 + static String getPinyin(String str) { + return PinyinHelper.getShortPinyin(str).substring(0, 1).toUpperCase(); + } + + /// 获取圆圈的背景 + static Color getCircleBg(String str) { + String pinyin = getPinyin(str); + return getCircleAvatarBg(pinyin); + } + + /// 获取头像背景颜色 + /// [key] 对照表中的key + static Color getCircleAvatarBg(String key) { + return circleAvatarMap[key]; + } + + static Color getChipBgColor(String name) { + String pinyin = PinyinHelper.getFirstWordPinyin(name); + pinyin = pinyin.substring(0, 1).toUpperCase(); + return nameToColor(pinyin); + } + + static Color nameToColor(String name) { + // assert(name.length > 1); + final int hash = name.hashCode & 0xffff; + final double hue = (360.0 * hash / (1 << 15)) % 360.0; + return HSVColor.fromAHSV(1.0, hue, 0.4, 0.90).toColor(); + } + + static String getTimeLine(BuildContext context, int timeMillis) { +// LogUtil.e("countryCode: " + +// Localizations.localeOf(context).countryCode + +// " languageCode: " + +// Localizations.localeOf(context).languageCode); + return TimelineUtil.format(timeMillis, + locale: Localizations.localeOf(context).languageCode, + dayFormat: DayFormat.Common); + } + + /// 计算标题字号 + /// [title] 标题 + static double getTitleFontSize(String title) { + // 小于10个字,18号字体 + if (ObjectUtil.isEmpty(title) || title.length < 10) { + return 18.0; + } + int count = 0; + List list = title.split(""); + for (int i = 0, length = list.length; i < length; i++) { + String ss = list[i]; + if (RegexUtil.isZh(ss)) { + count++; + } + } + //10个汉字或16个字符以上,14号字 + return (count >= 10 || title.length > 16) ? 14.0 : 18.0; + } + + /// 判断升级状态,如果远程版本小于等于当前按本,返回0 不升级, + /// 如果返回 1 升级 + /// > x 强升 + static int getUpdateStatus(String version, {String local}) { + if (ObjectUtil.isEmpty(version)) return 0; + String locVersion = local ?? AppConfig.version; + int remote = int.tryParse(version.replaceAll('.', '')); + int loc = int.tryParse(locVersion.replaceAll('.', '')); + if (remote <= loc) { + return 0; + } else { + return remote - loc; + } + } + + /// 获取加载状态 + static int getLoadStatus(bool hasError, List data) { + if (hasError) return LoadStatus.fail; + if (data == null) { + // data为空,加载中 + return LoadStatus.loading; + } else if (data.isEmpty) { + // data为空数组,返回空 + return LoadStatus.empty; + } else { + // + return LoadStatus.success; + } + } + + /// 字符串转列表 + /// [str] 待转字符串 如:[1,2,3,4,5] + static List strToList(String str) { + if (str == '') { + str = "[]"; + } + List list = convert.jsonDecode(str); + print(list); + return list; + } + + /// 列表转字符串 + /// [list] 待转列表 + static String listToStr(List list) { + String str = convert.jsonEncode(list); + print(str); + return str; + } +} diff --git a/lib/utils/version_util.dart b/lib/utils/version_util.dart new file mode 100644 index 0000000..1b92ecc --- /dev/null +++ b/lib/utils/version_util.dart @@ -0,0 +1,98 @@ +import 'dart:io'; + +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; +import 'package:install_apk_plugin/install_apk_plugin.dart'; + +import 'utils.dart'; + +/// 版本更新工具类 +class VersionUtil { + static final VersionUtil _singleton = VersionUtil._init(); + + static Dio _dio = Dio(); + + List listeners = List(); + + bool isDownload = false; + + factory VersionUtil() { + return _singleton; + } + + VersionUtil._init(); + + void downloadApk(String urlPath, String appId) async { + if (isDownload == true || ObjectUtil.isEmpty(urlPath)) return; + try { + await DirectoryUtil.getInstance(); + String apkDirPath = DirectoryUtil.getStoragePath(category: 'Download'); + LogUtil.e("apkDirPath: $apkDirPath"); + Directory apkDir = DirectoryUtil.createDirSync(apkDirPath); + + String apkName = Utils.getFileName(urlPath); + String apkPath = '$apkDirPath/$apkName'; + String apkTempPath = '$apkDirPath/temp_$apkName'; + + LogUtil.e("apkPath: $apkPath"); + LogUtil.e("apkTempPath: $apkTempPath"); + + File file = File(apkPath); + if (file.existsSync()) { + _install(apkPath, appId); + isDownload = false; + listeners.forEach((listener) { + listener(1, 1); + }); + return; + } + isDownload = true; + Response response = await _dio.download( + urlPath, + apkTempPath, + onProgress: (int count, int total) { + LogUtil.e( + "onReceiveProgress total: $total, count: $count, prect: ${count / total}"); + listeners.forEach((listener) { + listener(count, total); + }); + if (count == total) { + isDownload = false; + File file = File(apkTempPath); + File fileNew = file.copySync(apkPath); + file.deleteSync(); + _install(apkPath, appId); + } + }, + ); + } catch (e) { + LogUtil.e("download apk error: ${e?.toString()}"); + isDownload = false; + listeners.forEach((listener) { + listener(-1, 1); + }); + } + } + + void _install(String filePath, String appId) { + InstallPlugin.installApk(filePath, appId).then((result) { + LogUtil.e('install apk $result'); + }).catchError((error) { + LogUtil.e('install apk error: $error'); + }); + } + + void addListener(OnDownloadProgress listener) { + if (listener == null) return; + if (!listeners.contains(listener)) { + listeners.add(listener); + } + } + + void removeListener(OnDownloadProgress listener) { + if (listener == null) return; + if (listeners.contains(listener)) { + listeners.remove(listener); + } + } +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..74cac3b --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,640 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + amap_core_fluttify: + dependency: transitive + description: + name: amap_core_fluttify + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.9.5" + amap_map_fluttify: + dependency: "direct main" + description: + name: amap_map_fluttify + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.24.0+3" + archive: + dependency: transitive + description: + name: archive + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.13" + args: + dependency: transitive + description: + name: args + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.6.0" + asn1lib: + dependency: transitive + description: + name: asn1lib + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.5" + async: + dependency: transitive + description: + name: async + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.1" + azlistview: + dependency: "direct main" + description: + name: azlistview + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.2" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.3" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.14.12" + common_utils: + dependency: transitive + description: + name: common_utils + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.1" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.1" + cookie_jar: + dependency: transitive + description: + name: cookie_jar + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.8" + core_location_fluttify: + dependency: transitive + description: + name: core_location_fluttify + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.4" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.4" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.3" + decimal: + dependency: transitive + description: + name: decimal + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.5" + dio: + dependency: "direct main" + description: + name: dio + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.13" + encrypt: + dependency: "direct main" + description: + name: encrypt + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.0.2" + file: + dependency: transitive + description: + name: file + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.2.1" + fluintl: + dependency: "direct main" + description: + name: fluintl + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.3" + flukit: + dependency: "direct main" + description: + name: flukit + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + flustars: + dependency: "direct main" + description: + name: flustars + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.3" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.3" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.8" + 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" + foundation_fluttify: + dependency: transitive + description: + name: foundation_fluttify + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.8.11" + http: + dependency: transitive + description: + name: http + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.12.2" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.1.4" + image: + dependency: transitive + description: + name: image + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.12" + image_picker: + dependency: "direct main" + description: + name: image_picker + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.7+4" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + install_apk_plugin: + dependency: "direct main" + description: + name: install_apk_plugin + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" + intl: + dependency: transitive + description: + name: intl + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.16.1" + latlng: + dependency: transitive + description: + name: latlng + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.2" + lpinyin: + dependency: "direct main" + description: + name: lpinyin + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.9" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.12.6" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.8" + oktoast: + dependency: "direct main" + description: + name: oktoast + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.3.2" + path: + dependency: transitive + description: + name: path + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.6.4" + path_provider: + dependency: transitive + description: + name: path_provider + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.6.11" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1+2" + path_provider_macos: + dependency: transitive + description: + name: path_provider_macos + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.4+3" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + pedantic: + dependency: transitive + description: + name: pedantic + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.9.0" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.0.1+1" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.1" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.0" + photo_view: + dependency: "direct main" + description: + name: photo_view + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.9.2" + platform: + dependency: transitive + description: + name: platform + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.1" + platform_detect: + dependency: transitive + description: + name: platform_detect + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.4.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + pointycastle: + dependency: transitive + description: + name: pointycastle + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + process: + dependency: transitive + description: + name: process + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.13" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.4.4" + pull_to_refresh: + dependency: "direct main" + description: + name: pull_to_refresh + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.6" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.3" + rational: + dependency: transitive + description: + name: rational + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.8" + rxdart: + dependency: "direct main" + description: + name: rxdart + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.22.6" + share: + dependency: "direct main" + description: + name: share + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.4+3" + shared_preferences: + dependency: transitive + description: + name: shared_preferences + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.5.8" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.2+1" + shared_preferences_macos: + dependency: transitive + description: + name: shared_preferences_macos + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1+10" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.4" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.2+7" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.7.0" + sp_util: + dependency: transitive + description: + name: sp_util + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" + sqflite: + dependency: "direct main" + description: + name: sqflite + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.1" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2+1" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.9.3" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.5" + synchronized: + dependency: transitive + description: + name: synchronized + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.0+2" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.15" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.6" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.5.0" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1+1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1+7" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.7" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.2" + uuid: + dependency: transitive + description: + name: uuid + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.0" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.8" + webview_flutter: + dependency: "direct main" + description: + name: webview_flutter + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.22+1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.0" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.6.1" +sdks: + dart: ">=2.8.0 <3.0.0" + flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..5875161 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,138 @@ +name: base_app +description: A new Flutter project. + +# The following line prevents the package from being accidentally published to +# pub.dev using `pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# 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 used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +version: 1.0.0+1 + +environment: + sdk: ">=2.7.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + flutter_localizations: + sdk: flutter + # iOS style icons. + cupertino_icons: ^0.1.3 + # Flutter 常用工具类库 https://github.com/Sky24n/flustars + flustars: ^0.3.2 + # toast + oktoast: ^2.1.7 + # http请求 + dio: 1.0.13 + # 数据库 + sqflite: ^1.3.0+2 + # 单图上传 + image_picker: ^0.6.7 + # 图片预览 + photo_view: ^0.9.2 + #非对称加密包 + encrypt: ^4.0.2 + # Flutter 城市列表 https://github.com/flutterchina/azlistview + azlistview: ^0.1.2 + # 汉字转拼音库 https://github.com/flutterchina/lpinyin + lpinyin: ^1.0.9 + # bloc用rxdart插件 https://github.com/ReactiveX/rxdart + rxdart: ^0.22.6 + # Flutter 国际化/多语言库 https://github.com/Sky24n/fluintl + fluintl: ^0.1.3 + # UI工具包含下拉刷新,轮播图,快速滚动条,渐变进度条,城市选择器等https://github.com/flutterchina/flukit. + flukit: ^1.0.2 + # 显示来自网络的图片并将它们保存在缓存 https://github.com/renefloor/flutter_cached_network_image + cached_network_image: 2.0.0 + # 拨电话、发邮件、打开网址、打开第三方 https://github.com/flutter/plugins/tree/master/packages/url_launcher + url_launcher: ^5.4.5 + # 分享share + share: ^0.6.4+1 + # webview_flutter + webview_flutter: ^0.3.21 + # 安装apk插件 + install_apk_plugin: ^1.0.1 + # 上拉加载和下拉刷新的组件 https://github.com/peng8350/flutter_pulltorefresh + pull_to_refresh: 1.1.6 + # 权限请求插件 + permission_handler: ^5.0.0+hotfix.6 + # 高德地图 + amap_map_fluttify: ^0.24.0+3 + + + +dev_dependencies: + flutter_test: + sdk: flutter + +# 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. +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 + + # To add assets to your application, add an assets section, like this: + assets: + - assets/images/ic_login_bg.png + - assets/images/guide1.png + - assets/images/guide2.png + - assets/images/guide3.png + - assets/images/splash_bg.png + - assets/images/default_avatar.jpg + - assets/images/logo.png + - assets/images/ic_data_empty.png + - assets/images/ic_network_error.png + - assets/images/qidian.png + - assets/images/zhongdian.png + - assets/images/jingshi.png + - assets/keys/public_key.pem + - assets/icons/camera.png + - assets/icons/card.png + - assets/icons/global.png + - assets/icons/image.png + - assets/icons/magic.png + - assets/icons/position.png + - assets/icons/scan.png + - assets/icons/setting.png + - assets/icons/warning.png + - assets/icons/text.png + + # 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: IconFont + fonts: + - asset: assets/font/iconfont.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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ba9c33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# 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/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +/build/ + +# Web related +lib/generated_plugin_registrant.dart + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Exceptions to above rules. +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/.metadata b/.metadata new file mode 100644 index 0000000..6ac2303 --- /dev/null +++ b/.metadata @@ -0,0 +1,10 @@ +# 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: f7a6a7906be96d2288f5d63a5a54c515a6e987fe + channel: stable + +project_type: app diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..3287bb6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,13 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter", + "request": "launch", + "type": "dart" + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..02be806 --- /dev/null +++ b/README.md @@ -0,0 +1,16 @@ +# base_app + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook) + +For help getting started with Flutter, view our +[online documentation](https://flutter.dev/docs), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/android/.gitignore b/android/.gitignore new file mode 100644 index 0000000..bc2100d --- /dev/null +++ b/android/.gitignore @@ -0,0 +1,7 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java diff --git a/android/app/build.gradle b/android/app/build.gradle new file mode 100644 index 0000000..81ecaa3 --- /dev/null +++ b/android/app/build.gradle @@ -0,0 +1,75 @@ +def localProperties = new Properties() +def localPropertiesFile = rootProject.file('local.properties') +if (localPropertiesFile.exists()) { + localPropertiesFile.withReader('UTF-8') { reader -> + localProperties.load(reader) + } +} + +def flutterRoot = localProperties.getProperty('flutter.sdk') +if (flutterRoot == null) { + throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") +} + +def flutterVersionCode = localProperties.getProperty('flutter.versionCode') +if (flutterVersionCode == null) { + flutterVersionCode = '1' +} + +def flutterVersionName = localProperties.getProperty('flutter.versionName') +if (flutterVersionName == null) { + flutterVersionName = '1.0' +} + +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" + +android { + compileSdkVersion 28 + + sourceSets { + main.java.srcDirs += 'src/main/kotlin' + } + + lintOptions { + disable 'InvalidPackage' + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId "com.example.base_app" + minSdkVersion 16 + targetSdkVersion 28 + versionCode flutterVersionCode.toInteger() + versionName flutterVersionName + } + signingConfigs { + release { + keyAlias 'flutterkey' + keyPassword '19931010' + storeFile file('../flutterkey.jks') + storePassword '19931010' + } + } + + buildTypes { + debug { + signingConfig signingConfigs.release + } + profile { + signingConfig signingConfigs.release + } + release { + signingConfig signingConfigs.release + } + } +} + +flutter { + source '../..' +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..6964790 --- /dev/null +++ b/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + diff --git a/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt new file mode 100644 index 0000000..91463e2 --- /dev/null +++ b/android/app/src/main/kotlin/com/example/base_app/MainActivity.kt @@ -0,0 +1,6 @@ +package com.example.base_app + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity: FlutterActivity() { +} 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..304732f --- /dev/null +++ b/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Binary files 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 --- /dev/null +++ b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Binary files differ 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..1f83a33 --- /dev/null +++ b/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..49809ee --- /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..3100ad2 --- /dev/null +++ b/android/build.gradle @@ -0,0 +1,31 @@ +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + google() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:3.5.0' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +allprojects { + repositories { + google() + jcenter() + } +} + +rootProject.buildDir = '../build' +subprojects { + project.buildDir = "${rootProject.buildDir}/${project.name}" +} +subprojects { + project.evaluationDependsOn(':app') +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/android/flutterkey.jks b/android/flutterkey.jks new file mode 100644 index 0000000..c38980f --- /dev/null +++ b/android/flutterkey.jks Binary files differ diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000..38c8d45 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1,4 @@ +org.gradle.jvmargs=-Xmx1536M +android.enableR8=true +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..296b146 --- /dev/null +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Fri Jun 23 08:50:38 CEST 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle new file mode 100644 index 0000000..5a2f14f --- /dev/null +++ b/android/settings.gradle @@ -0,0 +1,15 @@ +include ':app' + +def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + +def plugins = new Properties() +def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') +if (pluginsFile.exists()) { + pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } +} + +plugins.each { name, path -> + def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() + include ":$name" + project(":$name").projectDir = pluginDirectory +} diff --git a/assets/font/iconfont.ttf b/assets/font/iconfont.ttf new file mode 100644 index 0000000..22a8f66 --- /dev/null +++ b/assets/font/iconfont.ttf Binary files differ diff --git a/assets/icons/camera.png b/assets/icons/camera.png new file mode 100644 index 0000000..2dfaa90 --- /dev/null +++ b/assets/icons/camera.png Binary files differ diff --git a/assets/icons/card.png b/assets/icons/card.png new file mode 100644 index 0000000..0ddcee8 --- /dev/null +++ b/assets/icons/card.png Binary files differ diff --git a/assets/icons/global.png b/assets/icons/global.png new file mode 100644 index 0000000..993a84f --- /dev/null +++ b/assets/icons/global.png Binary files differ diff --git a/assets/icons/image.png b/assets/icons/image.png new file mode 100644 index 0000000..1cfaecf --- /dev/null +++ b/assets/icons/image.png Binary files differ diff --git a/assets/icons/magic.png b/assets/icons/magic.png new file mode 100644 index 0000000..cc29619 --- /dev/null +++ b/assets/icons/magic.png Binary files differ diff --git a/assets/icons/position.png b/assets/icons/position.png new file mode 100644 index 0000000..f8a9a52 --- /dev/null +++ b/assets/icons/position.png Binary files differ diff --git a/assets/icons/scan.png b/assets/icons/scan.png new file mode 100644 index 0000000..b7ea1c2 --- /dev/null +++ b/assets/icons/scan.png Binary files differ diff --git a/assets/icons/setting.png b/assets/icons/setting.png new file mode 100644 index 0000000..0533de2 --- /dev/null +++ b/assets/icons/setting.png Binary files differ diff --git a/assets/icons/text.png b/assets/icons/text.png new file mode 100644 index 0000000..c551c79 --- /dev/null +++ b/assets/icons/text.png Binary files differ diff --git a/assets/icons/warning.png b/assets/icons/warning.png new file mode 100644 index 0000000..dcb3ce3 --- /dev/null +++ b/assets/icons/warning.png Binary files differ diff --git a/assets/images/1.5x/jingshi.png b/assets/images/1.5x/jingshi.png new file mode 100644 index 0000000..a60326d --- /dev/null +++ b/assets/images/1.5x/jingshi.png Binary files differ diff --git a/assets/images/1.5x/qidian.png b/assets/images/1.5x/qidian.png new file mode 100644 index 0000000..e2e0dbe --- /dev/null +++ b/assets/images/1.5x/qidian.png Binary files differ diff --git a/assets/images/1.5x/zhongdian.png b/assets/images/1.5x/zhongdian.png new file mode 100644 index 0000000..4db54d7 --- /dev/null +++ b/assets/images/1.5x/zhongdian.png Binary files differ diff --git a/assets/images/2.0x/jingshi.png b/assets/images/2.0x/jingshi.png new file mode 100644 index 0000000..a295809 --- /dev/null +++ b/assets/images/2.0x/jingshi.png Binary files differ diff --git a/assets/images/2.0x/qidian.png b/assets/images/2.0x/qidian.png new file mode 100644 index 0000000..b85a705 --- /dev/null +++ b/assets/images/2.0x/qidian.png Binary files differ diff --git a/assets/images/2.0x/zhongdian.png b/assets/images/2.0x/zhongdian.png new file mode 100644 index 0000000..759db30 --- /dev/null +++ b/assets/images/2.0x/zhongdian.png Binary files differ diff --git a/assets/images/3.0x/jingshi.png b/assets/images/3.0x/jingshi.png new file mode 100644 index 0000000..b5fb8e7 --- /dev/null +++ b/assets/images/3.0x/jingshi.png Binary files differ diff --git a/assets/images/3.0x/qidian.png b/assets/images/3.0x/qidian.png new file mode 100644 index 0000000..ab6910a --- /dev/null +++ b/assets/images/3.0x/qidian.png Binary files differ diff --git a/assets/images/3.0x/zhongdian.png b/assets/images/3.0x/zhongdian.png new file mode 100644 index 0000000..4241e88 --- /dev/null +++ b/assets/images/3.0x/zhongdian.png Binary files differ diff --git a/assets/images/default_avatar.jpg b/assets/images/default_avatar.jpg new file mode 100644 index 0000000..8e005a6 --- /dev/null +++ b/assets/images/default_avatar.jpg Binary files differ diff --git a/assets/images/guide1.png b/assets/images/guide1.png new file mode 100644 index 0000000..1114572 --- /dev/null +++ b/assets/images/guide1.png Binary files differ diff --git a/assets/images/guide2.png b/assets/images/guide2.png new file mode 100644 index 0000000..5395b59 --- /dev/null +++ b/assets/images/guide2.png Binary files differ diff --git a/assets/images/guide3.png b/assets/images/guide3.png new file mode 100644 index 0000000..98a52fa --- /dev/null +++ b/assets/images/guide3.png Binary files differ diff --git a/assets/images/ic_data_empty.png b/assets/images/ic_data_empty.png new file mode 100644 index 0000000..58c0f98 --- /dev/null +++ b/assets/images/ic_data_empty.png Binary files differ diff --git a/assets/images/ic_login_bg.png b/assets/images/ic_login_bg.png new file mode 100644 index 0000000..64789c3 --- /dev/null +++ b/assets/images/ic_login_bg.png Binary files differ diff --git a/assets/images/ic_network_error.png b/assets/images/ic_network_error.png new file mode 100644 index 0000000..7e9944f --- /dev/null +++ b/assets/images/ic_network_error.png Binary files differ diff --git a/assets/images/jingshi.png b/assets/images/jingshi.png new file mode 100644 index 0000000..16b1d05 --- /dev/null +++ b/assets/images/jingshi.png Binary files differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..240c897 --- /dev/null +++ b/assets/images/logo.png Binary files differ diff --git a/assets/images/qidian.png b/assets/images/qidian.png new file mode 100644 index 0000000..19b7106 --- /dev/null +++ b/assets/images/qidian.png Binary files differ diff --git a/assets/images/splash_bg.png b/assets/images/splash_bg.png new file mode 100644 index 0000000..074c768 --- /dev/null +++ b/assets/images/splash_bg.png Binary files differ diff --git a/assets/images/zhongdian.png b/assets/images/zhongdian.png new file mode 100644 index 0000000..02c2991 --- /dev/null +++ b/assets/images/zhongdian.png Binary files differ diff --git a/assets/keys/public_key.pem b/assets/keys/public_key.pem new file mode 100644 index 0000000..2e5cce1 --- /dev/null +++ b/assets/keys/public_key.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu5k8gcTFJy5UtMfmtKiR3f/Ec +Ue93kzfteRj6+sM5fHRvOib82+uqQMjgaRZiMcr3HiHIFY5vA6c+Rfb5R2COitoO +hxyA9U2eLXknzxLUQIAqXAvKQO8KnerA1Qjcds7xhJB2XPhWFlY4RVtMT2wr2lMd +29QDE4F/kzyDhNBpxwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file diff --git a/ios/.gitignore b/ios/.gitignore new file mode 100644 index 0000000..e96ef60 --- /dev/null +++ b/ios/.gitignore @@ -0,0 +1,32 @@ +*.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/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..6b4c0f7 --- /dev/null +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 8.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..d0b0763 --- /dev/null +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,506 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + 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 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 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 = ""; }; +/* 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 = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 97C146F11CF9000F007C117D /* Supporting Files */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; + 97C146F11CF9000F007C117D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 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 = { + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + 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 = 8.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + 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; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LIBRARY_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Flutter", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.baseApp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /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..a28140c --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..dc9ada4 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png Binary files 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..28c6bf0 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png Binary files 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..f091b6b --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png Binary files 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..4cde121 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png Binary files 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..d0ef06e --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png Binary files 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..dcdc230 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png Binary files 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..2ccbfd9 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png Binary files 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..c8f9ed8 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png Binary files 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..a6d6b86 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png Binary files 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..75b2d16 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png Binary files 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..c4df70d --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png Binary files 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..6a84f41 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png Binary files 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..d0e1f58 --- /dev/null +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png Binary files 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..0bedcf2 --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png Binary files 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..9da19ea --- /dev/null +++ b/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png Binary files 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..f2e259c --- /dev/null +++ b/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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..35bd7f1 --- /dev/null +++ b/ios/Runner/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + base_app + 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 + + UIViewControllerBasedStatusBarAppearance + + + 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/lib/blocs/application_bloc.dart b/lib/blocs/application_bloc.dart new file mode 100644 index 0000000..60eb47b --- /dev/null +++ b/lib/blocs/application_bloc.dart @@ -0,0 +1,38 @@ +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class ApplicationBloc implements BlocBase { + BehaviorSubject _appEvent = BehaviorSubject(); + // 入口 + Sink get _appEventSink => _appEvent.sink; + // 出口 + Stream get appEventStream => _appEvent.stream; + + @override + void dispose() { + _appEvent.close(); + } + + @override + Future getData({String labelId, int page}) { + // TODO: implement getData + return null; + } + + @override + Future onLoadMore({String labelId}) { + // TODO: implement onLoadMore + return null; + } + + @override + Future onRefresh({String labelId}) { + // TODO: implement onRefresh + return null; + } + + void sendAppEvent(int type) { + _appEventSink.add(type); + } +} diff --git a/lib/blocs/bloc_index.dart b/lib/blocs/bloc_index.dart new file mode 100644 index 0000000..c0f93b4 --- /dev/null +++ b/lib/blocs/bloc_index.dart @@ -0,0 +1,4 @@ +export 'bloc_provider.dart'; +export 'application_bloc.dart'; +export 'main_bloc.dart'; +export 'list_bloc.dart'; diff --git a/lib/blocs/bloc_provider.dart b/lib/blocs/bloc_provider.dart new file mode 100644 index 0000000..659f87c --- /dev/null +++ b/lib/blocs/bloc_provider.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; + +// 抽象类 +abstract class BlocBase { + //获取数据 + Future getData({String labelId, int page}); + // 刷新 + Future onRefresh({String labelId}); + // 加载更多 + Future onLoadMore({String labelId}); + + // 可用于Widget释放时能关闭Stream + void dispose(); +} + +/// 设计一个BlocProvider StatefulWidget来处理数据,接收两个参数 +/// [bloc] bloc对象 +/// [child] 子Widget +class BlocProvider extends StatefulWidget { + BlocProvider({ + Key key, + @required this.child, + @required this.bloc, + this.userDispose: true, + }) : super(key: key); + + final T bloc; + final Widget child; + final bool userDispose; + + @override + _BlocProviderState createState() => _BlocProviderState(); + + // 返回bloc + static T of(BuildContext context) { + // 通过遍历Element的parent来找到指定类型的Widget + BlocProvider provider = + context.findAncestorWidgetOfExactType>(); + return provider.bloc; + } + + // static Type _typeOf() => T; +} + +class _BlocProviderState extends State> { + @override + // 资源释放 + void dispose() { + if (widget.userDispose) widget.bloc.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return widget.child; + } +} diff --git a/lib/blocs/list_bloc.dart b/lib/blocs/list_bloc.dart new file mode 100644 index 0000000..a1af943 --- /dev/null +++ b/lib/blocs/list_bloc.dart @@ -0,0 +1,109 @@ +import 'dart:collection'; + +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/data/repository/article_repository.dart'; +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +/// 列表页面bloc(list_page) +class ListBloc implements BlocBase { + /// banner + //banner的controller + BehaviorSubject> _banner = + BehaviorSubject>(); + // banner入口sink + Sink> get _bannerSink => _banner.sink; + // banner出口stream + Stream> get bannerStream => _banner.stream; + // 访问后台的repository + CommonRepository commonRepository = new CommonRepository(); + + /// 文章列表 + BehaviorSubject> _article = + BehaviorSubject>(); + Sink> get _articleSink => _article.sink; + Stream> get articleStream => _article.stream; + ArticleRepository articleRepository = new ArticleRepository(); + // 构造器 + ListBloc() { + LogUtil.e("ListBloc......"); + } + + /// 获取数据 + /// [lableId] 那个页面的标识 + /// [page] //此处无用 + @override + Future getData({String labelId, int page}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onLoadMore({String labelId}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + @override + Future onRefresh({String labelId, bool isReload}) { + switch (labelId) { + case Ids.titleList: + return getHomeData(labelId); + break; + default: + return Future.delayed(new Duration(seconds: 1)); + break; + } + } + + Future getHomeData(String labelId) { + getArticleList(labelId, 1); + return getBanner(labelId); + } + + Future getArticleList(String labelId, offset) async { + ArticleListReq _articleReq = new ArticleListReq(offset, 10); + articleRepository.getArticleList(_articleReq).then((list) { + if (list.length > 6) { + list = list.sublist(0, 6); + } + _articleSink.add(UnmodifiableListView(list)); + }); + } + + // 获取滚动条幅 + Future getBanner(String labelId) { + return commonRepository.getBanner().then((list) { + // sink中推入数据 + _bannerSink.add(UnmodifiableListView(list)); + }).catchError((onError) { + _bannerSink.add([]); + }); + } + + @override + void dispose() { + _banner.close(); + } +} diff --git a/lib/blocs/main_bloc.dart b/lib/blocs/main_bloc.dart new file mode 100644 index 0000000..4597a5e --- /dev/null +++ b/lib/blocs/main_bloc.dart @@ -0,0 +1,90 @@ +import 'dart:collection'; + +import 'package:base_app/data/repository/common_repository.dart'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:rxdart/rxdart.dart'; + +import 'bloc_provider.dart'; + +class MainBloc implements BlocBase { + ///****** ****** ****** Banner ****** ****** ****** / + + // BehaviorSubject> _banner = + // BehaviorSubject>(); + + // Sink> get _bannerSink => _banner.sink; + + // Stream> get bannerStream => _banner.stream; + + ///****** ****** ****** 版本号 ****** ****** ****** / + + BehaviorSubject _version = BehaviorSubject(); + + Sink get _versionSink => _version.sink; + + Stream get versionStream => _version.stream.asBroadcastStream(); + + VersionModel _versionModel; + + ///****** ****** ****** Version ****** ****** ****** / + + ///****** ****** ****** personal ****** ****** ****** / + + CommonRepository commonRepository = new CommonRepository(); + + HttpUtils httpUtils = new HttpUtils(); + + MainBloc() { + LogUtil.e("MainBloc......"); + } + + @override + Future getData({String labelId, int page}) { + // switch (labelId) { + // case Ids.titleHome: + // return getHomeData(labelId); + // break; + // default: + // return Future.delayed(new Duration(seconds: 1)); + // break; + // } + } + + @override + Future onLoadMore({String labelId}) {} + + @override + Future onRefresh({String labelId, bool isReload}) {} + + // 获取主页数据 + // Future getHomeData(String labelId) { + // return getBanner(labelId); + // } + + // 获取滚动条幅 + // Future getBanner(String labelId) { + // return commonRepository.getBanner().then((list) { + // _bannerSink.add(UnmodifiableListView(list)); + // }); + // } + + Future getVersion() async { + httpUtils.getVersion().then((model) { + _versionModel = model; + _versionSink.add(_versionModel); + }); + } + + void test() { + LogUtil.e("MainBloc test 1....."); + } + + @override + void dispose() { + // _banner.close(); + } +} diff --git a/lib/common/common.dart b/lib/common/common.dart new file mode 100644 index 0000000..b984b50 --- /dev/null +++ b/lib/common/common.dart @@ -0,0 +1,48 @@ +import 'package:flutter/foundation.dart'; + +class BaseConstant { + static const String keyShowGuide = 'show_guide'; // 是否显示导航,无用 + static const String serverAddress = + "http://rest.apizza.net/mock/cfbb939c147bb6d68372de83af189fee/"; + static const String keyAccount = 'username'; // 用户名 + static const String keyPassword = 'password'; // 密码 + static const String keyUserName = 'user_name'; // 用户名:姓名 + static const String keyUserModel = 'user_model'; // 用户对象 + static const String keyPublicKey = 'public_key'; // 公钥 + static const String keyAppToken = 'token'; // token + static const String keyReadFormLocal = 'read_local'; // 是否仅读取本地数据 + + // 路由常量 + static const String routeMain = 'route_main'; // 主页 + static const String routeLogin = 'route_login'; // 登录页 + static const String routeAddInspection = 'demo'; // demo列表页 + static const String routeSetting = 'route_setting'; // 系统设置页 +} + +class Constant { + static const String keyLanguage = 'key_language'; // 语言 + static const int status_success = 200; // 成功状态 + static const int type_sys_update = 1; // 系统更新 + static const int type_refresh_all = 5; //? + + static const String key_theme_color = 'key_theme_color'; + static const String key_guide = 'key_guide'; + static const String key_splash_model = 'key_splash_models'; + static const String key_url = 'key_url'; +} + +// App配置 +class AppConfig { + static const String appId = 'com.casic.flutter.base'; // appId + static const String appName = 'flutter框架及示例'; // app名称 + static const String version = '1.0'; // 版本 + static const bool isDebug = kDebugMode; +} + +// 网络请求状态 +class LoadStatus { + static const int fail = 500; // 失败 + static const int loading = 0; + static const int success = 200; // 成功 + static const int empty = 2; +} diff --git a/lib/common/component_index.dart b/lib/common/component_index.dart new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/lib/common/component_index.dart diff --git a/lib/common/global.dart b/lib/common/global.dart new file mode 100644 index 0000000..f8a64b3 --- /dev/null +++ b/lib/common/global.dart @@ -0,0 +1,45 @@ +import 'dart:io'; + +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter/widgets.dart'; + +import 'package:base_app/common/common.dart'; + +class Global { + //初始化全局信息 + static Future init(VoidCallback callback) async { + WidgetsFlutterBinding.ensureInitialized(); + await SpUtil.getInstance(); + // 系统初始化配置 + String readFormLocal = SpUtil.getString(BaseConstant.keyReadFormLocal); + if (readFormLocal == null || readFormLocal == "") { + // 默认使用网络 + SpUtil.putString(BaseConstant.keyReadFormLocal, "false"); + } + // 临时测试用,重置url + // SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + + String baseUrl = SpUtil.getString(Constant.key_url); + if (baseUrl == null || baseUrl == "") { + SpUtil.putString(Constant.key_url, BaseConstant.serverAddress); // 请求ip和端口 + } + + // 设置强制竖屏 + if (Platform.isAndroid) { + // 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。 + SystemUiOverlayStyle systemUiOverlayStyle = + SystemUiOverlayStyle(statusBarColor: Colors.transparent); + SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); + // 强制竖屏 + SystemChrome.setPreferredOrientations( + [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); + } + callback(); + } +} + +class Router { + static GlobalKey navigatorKey = GlobalKey(); +} diff --git a/lib/common/sp_helper.dart b/lib/common/sp_helper.dart new file mode 100644 index 0000000..ebc9b9c --- /dev/null +++ b/lib/common/sp_helper.dart @@ -0,0 +1,42 @@ +import 'package:flustars/flustars.dart'; + +import 'common.dart'; + +class SpHelper { + /// T 用于区分存储类型 + /// Example. + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// SpHelper.putObject(key, value); + /// + /// SpHelper.putObject(key, UserModel); + /// + static void putObject(String key, Object value) { + switch (T) { + case int: + SpUtil.putInt(key, value); + break; + case double: + SpUtil.putDouble(key, value); + break; + case bool: + SpUtil.putBool(key, value); + break; + case String: + SpUtil.putString(key, value); + break; + case List: + SpUtil.putStringList(key, value); + break; + default: + SpUtil.putObject(key, value); + break; + } + } + + static String getThemeColor() { + return SpUtil.getString(Constant.key_theme_color, defValue: 'blue'); + } +} diff --git a/lib/data/api/apis.dart b/lib/data/api/apis.dart new file mode 100644 index 0000000..a66b4d8 --- /dev/null +++ b/lib/data/api/apis.dart @@ -0,0 +1,29 @@ +class AppApi { + static const String BANNER = 'banner'; + static const String BASE_CONFIG = 'config/baseConfig'; // 获取系统配置接口,登录前用 + static const String IMAGE_UPLOAD = 'fileUpload'; // 图片上传 + static const String IMAGE_STATIC = 'static/'; // 图片显示静态路径 + static const String USER_LOGIN = "user/appLogin"; //登录 + static const String USER_LOGOUT = "user/logout"; //退出 + static const String USER_INFO = "user/info"; // 获取用户信息 + + // 巡检记录 + static const String inspection_list = 'inspection/search'; // 巡检记录列表 + static const String inspection_add = 'inspection/add'; // 添加巡检记录 + static const String inspection_info = 'inspection/info'; // 巡检记录详情 + + // 文章 + static const String article_list = 'article/list'; // 文章列表 + + // 拼接url + static String getPath({String path: '', int page, String resType: ''}) { + StringBuffer sb = new StringBuffer(path); + if (page != null) { + sb.write('/$page'); + } + if (resType != null && resType.isNotEmpty) { + sb.write('/$resType'); + } + return sb.toString(); + } +} diff --git a/lib/data/net/dio_util.dart b/lib/data/net/dio_util.dart new file mode 100644 index 0000000..837affa --- /dev/null +++ b/lib/data/net/dio_util.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/global.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; + +/// 请求方法. +class Method { + static final String get = "GET"; + static final String post = "POST"; + static final String put = "PUT"; + static final String head = "HEAD"; + static final String delete = "DELETE"; + static final String patch = "PATCH"; +} + +///Http配置. +class HttpConfig { + /// constructor. + HttpConfig({ + this.status, + this.code, + this.msg, + this.data, + this.options, + this.pem, + this.pKCSPath, + this.pKCSPwd, + }); + + /// BaseResp [String status]字段 key, 默认:status. + String status; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String code; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String msg; + + /// BaseResp [T data]字段 key, 默认:data. + String data; + + /// Options. + Options options; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PEM证书内容. + String pem; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书路径. + String pKCSPath; + + /// 详细使用请查看dio官网 https://github.com/flutterchina/dio/blob/flutter/README-ZH.md#Https证书校验. + /// PKCS12 证书密码. + String pKCSPwd; +} + +/// 单例 DioUtil. +/// debug模式下可以打印请求日志. DioUtil.openDebug(). +/// dio详细使用请查看dio官网(https://github.com/flutterchina/dio). +class DioUtil { + static final DioUtil _singleton = DioUtil._init(); + static Dio _dio; + + /// BaseResp [String status]字段 key, 默认:status. + String _statusKey = "success"; + + /// BaseResp [int code]字段 key, 默认:errorCode. + String _codeKey = "code"; + + /// BaseResp [String msg]字段 key, 默认:errorMsg. + String _msgKey = "message"; + + /// BaseResp [T data]字段 key, 默认:data. + String _dataKey = "data"; + + /// Options. + Options _options = getDefOptions(); + + /// PEM证书内容. + String _pem; + + /// PKCS12 证书路径. + String _pKCSPath; + + /// PKCS12 证书密码. + String _pKCSPwd; + + /// 是否是debug模式. + static bool _isDebug = false; + + static DioUtil getInstance() { + return _singleton; + } + + factory DioUtil() { + return _singleton; + } + + DioUtil._init() { + _dio = new Dio(_options); + } + + /// 打开debug模式. + static void openDebug() { + _isDebug = true; + } + + void setCookie(String cookie) { + Map _headers = new Map(); + _headers["Cookie"] = cookie; + _dio.options.headers.addAll(_headers); + } + void setToken(String token) { + Map _headers = new Map(); + _headers["token"] = token; + _dio.options.headers.addAll(_headers); + } + + /// set Config. + void setConfig(HttpConfig config) { + _statusKey = config.status ?? _statusKey; + _codeKey = config.code ?? _codeKey; + _msgKey = config.msg ?? _msgKey; + _dataKey = config.data ?? _dataKey; + _mergeOption(config.options); + _pem = config.pem ?? _pem; + if (_dio != null) { + _dio.options = _options; + if (_pem != null) { + _dio.onHttpClientCreate = (HttpClient client) { + client.badCertificateCallback = + (X509Certificate cert, String host, int port) { + if (cert.pem == _pem) { + // 证书一致,则放行 + return true; + } + return false; + }; + }; + } + if (_pKCSPath != null) { + _dio.onHttpClientCreate = (HttpClient client) { + SecurityContext sc = new SecurityContext(); + //file为证书路径 + sc.setTrustedCertificates(_pKCSPath, password: _pKCSPwd); + HttpClient httpClient = new HttpClient(context: sc); + return httpClient; + }; + } + } + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data . + Future> request(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = (response.data[_codeKey] is String) + ? int.tryParse(response.data[_codeKey]) + : response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = (_dataMap[_statusKey] is int) + ? _dataMap[_statusKey].toString() + : _dataMap[_statusKey]; + _code = (_dataMap[_codeKey] is String) + ? int.tryParse(_dataMap[_codeKey]) + : _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = _dataMap[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseResp(_status, _code, _msg, _data); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Make http request with options. + /// [method] The request method. + /// [path] The url path. + /// [data] The request data + /// [options] The request options. + /// 返回 status code msg data Response. + Future> requestR(String method, String path, + {data, Options options, CancelToken cancelToken}) async { + // if(options==null){options = _dio.options;} + Response response = await _dio.request(path, + data: data, + options: _checkOptions(method, options), + cancelToken: cancelToken); + print(path); + _printHttpLog(response); + bool _status; + int _code; + String _msg; + dynamic _data; + if (response.statusCode == HttpStatus.ok || + response.statusCode == HttpStatus.created) { + try { + if (response.data is Map) { + _status = response.data[_statusKey]; + _code = response.data[_codeKey]; + _msg = response.data[_msgKey]; + _data = response.data[_dataKey]; + } else { + Map _dataMap = _decodeData(response); + _status = response.data[_statusKey]; + _code = _dataMap[_codeKey]; + _msg = _dataMap[_msgKey]; + _data = response.data[_dataKey]; + } + if(_code==401){ + Router.navigatorKey.currentState.pushNamedAndRemoveUntil(BaseConstant.routeLogin, ModalRoute.withName("/")); + } + return new BaseRespR(_status, _code, _msg, _data, response); + } catch (e) { + return new Future.error(new DioError( + response: response, + message: "data parsing exception...", + type: DioErrorType.RESPONSE, + )); + } + } + return new Future.error(new DioError( + response: response, + message: "statusCode: $response.statusCode, service error", + type: DioErrorType.RESPONSE, + )); + } + + /// Download the file and save it in local. The default http method is "GET",you can custom it by [Options.method]. + /// [urlPath]: The file url. + /// [savePath]: The path to save the downloading file later. + /// [onProgress]: The callback to listen downloading progress.please refer to [OnDownloadProgress]. + Future download( + String urlPath, + savePath, { + OnDownloadProgress onProgress, + CancelToken cancelToken, + data, + Options options, + }) { + return _dio.download(urlPath, savePath, + onProgress: onProgress, + cancelToken: cancelToken, + data: data, + options: options); + } + + /// decode response data. + Map _decodeData(Response response) { + if (response == null || + response.data == null || + response.data.toString().isEmpty) { + return new Map(); + } + return json.decode(response.data.toString()); + } + + /// check Options. + Options _checkOptions(method, options) { + if (options == null) { + options = new Options(); + } + options.method = method; + return options; + } + + /// merge Option. + void _mergeOption(Options opt) { + _options.method = opt.method ?? _options.method; + _options.headers = (new Map.from(_options.headers))..addAll(opt.headers); + _options.baseUrl = opt.baseUrl ?? _options.baseUrl; + _options.connectTimeout = opt.connectTimeout ?? _options.connectTimeout; + _options.receiveTimeout = opt.receiveTimeout ?? _options.receiveTimeout; + _options.responseType = opt.responseType ?? _options.responseType; + _options.data = opt.data ?? _options.data; + _options.extra = (new Map.from(_options.extra))..addAll(opt.extra); + _options.contentType = opt.contentType ?? _options.contentType; + _options.validateStatus = opt.validateStatus ?? _options.validateStatus; + _options.followRedirects = opt.followRedirects ?? _options.followRedirects; + } + + /// print Http Log. + void _printHttpLog(Response response) { + if (!_isDebug) { + return; + } + try { + print("----------------Http Log----------------" + + "\n[statusCode]: " + + response.statusCode.toString() + + "\n[request ]: " + + _getOptionsStr(response.request)); + _printDataStr("reqdata ", response.request.data); + _printDataStr("response", response.data); + } catch (ex) { + print("Http Log" + " error......"); + } + } + + /// get Options Str. + String _getOptionsStr(Options request) { + return "method: " + + request.method + + " baseUrl: " + + request.baseUrl + + " path: " + + request.path; + } + + /// print Data Str. + void _printDataStr(String tag, Object value) { + String da = value.toString(); + while (da.isNotEmpty) { + if (da.length > 512) { + print("[$tag ]: " + da.substring(0, 512)); + da = da.substring(512, da.length); + } else { + print("[$tag ]: " + da); + da = ""; + } + } + } + + /// get dio. + Dio getDio() { + return _dio; + } + + /// create new dio. + static Dio createNewDio([Options options]) { + options = options ?? getDefOptions(); + Dio dio = new Dio(options); + return dio; + } + + /// get Def Options. + static Options getDefOptions() { + Options options = new Options(); + options.contentType = + ContentType.parse("application/x-www-form-urlencoded"); + options.connectTimeout = 1000 * 30; + options.receiveTimeout = 1000 * 30; + return options; + } +} diff --git a/lib/data/protocol/base_resp.dart b/lib/data/protocol/base_resp.dart new file mode 100644 index 0000000..483f859 --- /dev/null +++ b/lib/data/protocol/base_resp.dart @@ -0,0 +1,44 @@ +import 'package:dio/dio.dart'; +/// 基础返回类 +/// 返回 success code message data. +class BaseResp { + bool success; + int code; + String message; + dynamic data; + + BaseResp(this.success, this.code, this.message, this.data); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} + +/// 返回 success code message data Response. +class BaseRespR { + bool success; + int code; + String message; + dynamic data; + Response response; + + BaseRespR(this.success, this.code, this.message, this.data, this.response); + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"success\":\"$success\""); + sb.write(",\"code\":$code"); + sb.write(",\"message\":\"$message\""); + sb.write(",\"data\":\"$data\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/protocol/model.dart b/lib/data/protocol/model.dart new file mode 100644 index 0000000..231aeb0 --- /dev/null +++ b/lib/data/protocol/model.dart @@ -0,0 +1,153 @@ +// 查询巡检记录返回数据 +import 'package:dio/dio.dart'; + +class InspectionData { + int size; + List datas; + InspectionData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 查询事件记录返回数据 +class TaskData { + int size; + List datas; + TaskData.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} + +// 获取巡检记录的请求 +class InspectionListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + InspectionListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + InspectionListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +// 获取事件记录的请求 +class TaskListReq { + String startTime; + String endTime; + String keywords; + int offset; + int limit; + + TaskListReq( + this.startTime, this.endTime, this.keywords, this.offset, this.limit); + + TaskListReq.fromJson(Map json) + : startTime = json['startTime'], + endTime = json['endTime'], + keywords = json['keywords'], + offset = json['offset'], + limit = json['limit']; + + Map toJson() => { + 'startTime': startTime == '' ? startTime : startTime + ' 00:00:00', + 'endTime': endTime == '' ? endTime : endTime + ' 23:59:59', + 'keywords': keywords, + 'offset': offset, + 'limit': limit + }; + + FormData toFormData() { + return FormData.from(toJson()); + } + + @override + String toString() { + return '{' + + " \"startTime\":\"" + + startTime + + "\"," + + " \"endTime\":\"" + + endTime + + "\"" + + " \"keywords\":\"" + + keywords + + "\"" + + " \"offset\":\"" + + offset.toString() + + "\"" + + " \"limit\":\"" + + limit.toString() + + "\"" + + '}'; + } +} + +class ArticleListReq { + final int offset; + final int limit; + final String order; + final String sort; + + ArticleListReq(this.offset, this.limit, {this.order, this.sort}); + + ArticleListReq.fromJson(Map json) + : offset = json['offset'], + limit = json['limit'], + order = json['order'], + sort = json['sort']; + + Map toJson() => { + 'offset': offset, + }; + FormData toFormData() { + return FormData.from(toJson()); + } +} + +class ArticleListResp { + int size; + List datas; + ArticleListResp.fromJson(Map json) + : size = json['total'], + datas = json['rows']; +} diff --git a/lib/data/protocol/user_model.dart b/lib/data/protocol/user_model.dart new file mode 100644 index 0000000..adbcb7f --- /dev/null +++ b/lib/data/protocol/user_model.dart @@ -0,0 +1,69 @@ +import 'package:dio/dio.dart'; + +/// 登录请求类 +class LoginReq { + String username; // 用户名 + String password; // 密码 + + LoginReq(username, password) { + this.username = username; + this.password = password; + } + + LoginReq.fromJson(Map json) + : username = json['username'], + password = json['password']; + + Map toJson() => { + 'username': username, + 'password': password, + }; + + FormData toFormData() { + return FormData.from({'username': username, 'password': password}); + } + + @override + String toString() { + return '{' + + " \"username\":\"" + + username + + "\"" + + ", \"password\":\"" + + password + + "\"" + + '}'; + } +} + +/// 用户Model,user/info接口返回对象 +class UserModel { + String name; // 姓名 + String id; // id + String username; // 账户 + String phone; // 手机号 + + UserModel.fromJson(Map json) + : name = json['name'], + id = json['id'], + username = json['account'], + phone = json['phone']; + + Map toJson() => { + 'name': name, + 'id': id, + 'username': username, + 'phone': phone, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"name\":\"$name\""); + sb.write(",\"id\":$id"); + sb.write(",\"username\":\"$username\""); + sb.write(",\"phone\":\"$phone\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/data/repository/article_repository.dart b/lib/data/repository/article_repository.dart new file mode 100644 index 0000000..e2c2b2b --- /dev/null +++ b/lib/data/repository/article_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/models.dart'; +import 'package:dio/dio.dart'; + +class ArticleRepository { + // 文章列表 + Future> getArticleList(ArticleListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>( + Method.get, AppApi.getPath(path: AppApi.article_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + ArticleListResp articlelist = ArticleListResp.fromJson(baseResp.data); + list = articlelist.datas?.map((value) { + ArticleModel model = ArticleModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取文章内容 + // Future getArticleInfo(String id) async { + // FormData params = FormData.from({'id': id}); + // BaseResp> baseResp = await DioUtil() + // .request>( + // Method.get, AppApi.getPath(path: AppApi.Article_info, resType: ''), + // data: params); + // if (baseResp.code != Constant.status_success) { + // return new Future.error(baseResp.message); + // } + // ArticleModel model; + // if (baseResp.data != null) { + // model = ArticleModel.fromJson(baseResp.data); + // } + // return model; + // } +} diff --git a/lib/data/repository/common_repository.dart b/lib/data/repository/common_repository.dart new file mode 100644 index 0000000..808205d --- /dev/null +++ b/lib/data/repository/common_repository.dart @@ -0,0 +1,43 @@ +import 'dart:io'; +import 'package:base_app/models/common/banner_model.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:dio/dio.dart'; + +class CommonRepository { + // 上传图片 + Future uploadImage(PickedFile image) async { + String path = image.path; + var name = path.substring(path.lastIndexOf("/") + 1, path.length); + FormData formData = + new FormData.from({"file": new UploadFileInfo(new File(path), name)}); + + BaseResp baseResp = await DioUtil().request( + Method.post, AppApi.getPath(path: AppApi.IMAGE_UPLOAD), + data: formData); + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return baseResp.data; + } + } + + // 获取banner + Future> getBanner() async { + BaseResp baseResp = await DioUtil() + .request(Method.get, AppApi.getPath(path: AppApi.BANNER)); + List bannerList; + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + if (baseResp.data != null) { + bannerList = baseResp.data.map((value) { + return BannerModel.fromJson(value); + }).toList(); + } + return bannerList; + } +} diff --git a/lib/data/repository/inspection_repository.dart b/lib/data/repository/inspection_repository.dart new file mode 100644 index 0000000..53fae85 --- /dev/null +++ b/lib/data/repository/inspection_repository.dart @@ -0,0 +1,48 @@ +import 'dart:io'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/model.dart'; +import 'package:base_app/models/inspectionModel.dart'; +import 'package:dio/dio.dart'; + +class InspectionRepository { + // 获取巡检记录 + Future> getInspectionList(InspectionListReq req) async { + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_list, resType: ''), + data: req.toFormData()); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + List list; + if (baseResp.data != null) { + InspectionData inspectionData = InspectionData.fromJson(baseResp.data); + list = inspectionData.datas?.map((value) { + InspectionModel model = InspectionModel.fromJson(value); + return model; + })?.toList(); + } + return list; + } + + // 获取巡检详情 + Future getInspectionInfo(String id) async { + FormData params = FormData.from({'id': id}); + BaseResp> baseResp = await DioUtil() + .request>(Method.get, + AppApi.getPath(path: AppApi.inspection_info, resType: ''), + data: params); + if (baseResp.code != Constant.status_success) { + return new Future.error(baseResp.message); + } + InspectionModel model; + if (baseResp.data != null) { + model = InspectionModel.fromJson(baseResp.data); + } + return model; + } +} diff --git a/lib/data/repository/user_repository.dart b/lib/data/repository/user_repository.dart new file mode 100644 index 0000000..c04cb97 --- /dev/null +++ b/lib/data/repository/user_repository.dart @@ -0,0 +1,100 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/common/sp_helper.dart'; +import 'package:base_app/data/api/apis.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/base_resp.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:encrypt/encrypt.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/services.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +/// 与用户相关请求后台仓库 +class UserRepository { + /// 获取公钥接口 + Future baseConfig() async { + // 调用登录接口 + BaseRespR> baseResp = + await DioUtil().requestR>( + Method.get, + AppApi.BASE_CONFIG, + ); + // 获取失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token保存 + if (baseResp.data != null) { + String publicKey = baseResp.data['publicKey']; + SpHelper.putObject(BaseConstant.keyPublicKey, publicKey); + return true; + } else { + return false; + } + } + + /// 登录并获取用户基本信息 + /// [req] 登录请求对象(username,password) + Future login(LoginReq req) async { + // 1. 加密 + String publicKeyStr = + await rootBundle.loadString('assets/keys/public_key.pem'); + RSAPublicKey publicKey = RSAKeyParser().parse(publicKeyStr); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + final encrypted = encrypter.encrypt(req.password); + print(encrypted.base64); + req.password = encrypted.base64; + // 2.调用登录接口 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.post, AppApi.USER_LOGIN, + data: req.toFormData()); + // 登录失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } + //登录成功,将token存在cookie + if (baseResp.data != null) { + String token = baseResp.data['token']; + LogUtil.e("token: " + token); + SpUtil.putString(BaseConstant.keyAppToken, token); + SpUtil.putString(BaseConstant.keyUserName, req.username); + DioUtil().setToken(token); + } + // 获取用户信息 + baseResp = await DioUtil().requestR>( + Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + // 获取用户信息 + Future getUserInfo() async { + // 获取用户信息 + BaseRespR> baseResp = await DioUtil() + .requestR>(Method.get, AppApi.USER_INFO, + data: null); + if (baseResp.code != Constant.status_success) { + return Future.error('获取用户信息失败!请退出重试'); + } + UserModel model = UserModel.fromJson(baseResp.data); + SpUtil.putObject(BaseConstant.keyUserModel, model); + return model; + } + + /// 注销 + Future logout() async { + // 调用登录接口 + BaseRespR baseResp = + await DioUtil().requestR(Method.get, AppApi.USER_LOGOUT); + // 注销失败 + if (baseResp.code != Constant.status_success) { + return Future.error(baseResp.message); + } else { + return true; + } + } +} diff --git a/lib/db/baseDbProvider.dart b/lib/db/baseDbProvider.dart new file mode 100644 index 0000000..68322c6 --- /dev/null +++ b/lib/db/baseDbProvider.dart @@ -0,0 +1,41 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:meta/meta.dart'; + +import 'sqlManager.dart'; + +/// Description:数据库表操作,实际操作表需要继承该类 +abstract class BaseDbProvider { + bool isTableExits = false; + + createTableString(); + + tableName(); + + ///创建表sql语句 + tableBaseString(String sql) { + return sql; + } + + // 获取数据库 + Future getDataBase() async { + return await open(); + } + + ///super 函数对父类进行初始化 + @mustCallSuper + prepare(name, String createSql) async { + isTableExits = await SqlManager.isTableExits(name); + if (!isTableExits) { + Database db = await SqlManager.getCurrentDatabase(); + return await db.execute(createSql); + } + } + + @mustCallSuper + open() async { + if (!isTableExits) { + await prepare(tableName(), createTableString()); + } + return await SqlManager.getCurrentDatabase(); + } +} diff --git a/lib/db/provider/InspectionDbProvider.dart b/lib/db/provider/InspectionDbProvider.dart new file mode 100644 index 0000000..4dd64bb --- /dev/null +++ b/lib/db/provider/InspectionDbProvider.dart @@ -0,0 +1,162 @@ +import 'package:base_app/models/inspectionModel.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flustars/flustars.dart'; +import 'package:sqflite/sqlite_api.dart'; +import '../baseDbProvider.dart'; + +/// Description: 巡检记录数据库操作类 + +class InspectionDbProvider extends BaseDbProvider { + ///表名 + final String name = 'InspectionList'; + + final String columnId = "id"; + final String columnName = "name"; + final String columnStartTime = "startTime"; + final String columnEndTime = "endTime"; + final String columnDate = "date"; + final String columnStartLng = "startLng"; + final String columnStartLat = "startLat"; + final String columnEndLng = "endLng"; + final String columnEndLat = "endLat"; + final String columnRoutes = "routes"; + final String columnUser = "user"; + + InspectionDbProvider(); + + @override + tableName() { + return name; + } + + @override + createTableString() { + return ''' + create table $name ( + $columnId TEXT primary key, + $columnName TEXT not null, + $columnStartTime DateTime not null, + $columnEndTime DateTime not null, + $columnDate TEXT not null, + $columnStartLng REAL not null, + $columnStartLat REAL not null, + $columnEndLng REAL not null, + $columnEndLat REAL not null, + $columnRoutes text not null, + $columnUser text not null + ) + '''; + } + + ///查询数据库 + Future _getInspectionProvider(Database db, String id) async { + List> maps = + await db.rawQuery("select * from $name where $columnId = '$id'"); + return maps; + } + + ///插入到数据库 + Future insert(InspectionModel model) async { + Database db = await getDataBase(); + var inspectionProvider = await _getInspectionProvider(db, model.id); + if (inspectionProvider != null) { + ///删除数据 + await db.delete(name, where: "$columnId = ?", whereArgs: [model.id]); + } + double startLng = model.startLng; + double startLat = model.startLat; + double endLng = model.endLng; + double endLat = model.endLat; + String routes = ""; + + String insertSql = ''' + INSERT INTO $name ($columnId,$columnName,$columnStartTime,$columnEndTime, + $columnDate,$columnStartLng,$columnStartLat,$columnEndLng,$columnEndLat, + $columnRoutes,$columnUser) + VALUES('${model.id}','${model.name}','${model.startTime}','${model.endTime}','${model.date}',$startLng,$startLat,$endLng,$endLat,'$routes','${model.user}') + '''; + print(insertSql); + // return await db.rawInsert(insertSql,[model.id,model.name,model.startTime,model.endTime,model.date, startLng, startLat, endLng, endLat,routes, model.user]); + + return await db.rawInsert(insertSql); + } + + ///更新数据库 + Future update(InspectionModel model) async { + // Database database = await getDataBase(); + // await database.rawUpdate( + // "update $name set $columnMobile = ?,$columnHeadImage = ? where $columnId= ?",[model.mobile,model.headImage,model.id]); + } + + ///获取事件数据_——详情 + Future getInspectionInfo(String id) async { + Database db = await getDataBase(); + List> maps = await _getInspectionProvider(db, id); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + if (list.length > 0) { + return list[0]; + } else { + return null; + } + } + + ///查询数据库 + Future> getInspections( + String startTime, String endTime, String keywords) async { + Database db = await getDataBase(); + String querySql = + "select * from $name where $columnName LIKE '%$keywords%'"; + if (startTime.length > 0) { + querySql += " and $columnStartTime>='$startTime 00:00:00' "; + } + if (endTime.length > 0) { + querySql += " and $columnStartTime<='$endTime 23:59:59' "; + } + LogUtil.e(querySql); + print(querySql); + List> maps = await db.rawQuery(querySql); + List list = []; + for (int i = 0; i < maps.length; i++) { + final item = maps[i]; + String id = item[columnId]; + String name = item[columnName]; + String startTime = item[columnStartTime]; + String endTime = item[columnEndTime]; + // String date = item[columnDate]; + double startLng = item[columnStartLng]; + double startLat = item[columnStartLat]; + double endLng = item[columnEndLng]; + double endLat = item[columnEndLat]; + String routesStr = item[columnRoutes]; + List route = []; + String user = item[columnUser]; + InspectionModel m = new InspectionModel(id, name, startTime, endTime, + startLng, startLat, endLng, endLat, route, [], user); + list.add(m); + } + return list; + } + + /// 清空数据库表 + Future deleteAll() async { + Database database = await getDataBase(); + await database.delete(name); + } +} diff --git a/lib/db/sqlManager.dart b/lib/db/sqlManager.dart new file mode 100644 index 0000000..a10f06c --- /dev/null +++ b/lib/db/sqlManager.dart @@ -0,0 +1,40 @@ +import 'package:sqflite/sqflite.dart'; +import 'package:path/path.dart'; + +/// Package: db +/// Description:数据库管理 +class SqlManager { + static const _VERSION = 1; // 版本 + static const _NAME = "xunjian.db"; // 数据库名 + static Database _database; // 数据库 + + ///初始化 + static init() async { + var databasesPath = await getDatabasesPath(); + String path = join(databasesPath, _NAME); + _database = await openDatabase(path, + version: _VERSION, onCreate: (Database db, int version) async {}); + } + + ///判断表是否存在 + static isTableExits(String tableName) async { + await getCurrentDatabase(); + var res = await _database.rawQuery( + "select * from Sqlite_master where type = 'table' and name = '$tableName'"); + return res != null && res.length > 0; + } + + ///获取当前数据库对象 + static Future getCurrentDatabase() async { + if (_database == null) { + await init(); + } + return _database; + } + + ///关闭 + static close() { + _database?.close(); + _database = null; + } +} diff --git a/lib/demos/city_select_page.dart b/lib/demos/city_select_page.dart new file mode 100644 index 0000000..02d7fb7 --- /dev/null +++ b/lib/demos/city_select_page.dart @@ -0,0 +1,177 @@ +import 'dart:convert'; + +import 'package:azlistview/azlistview.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityInfo extends ISuspensionBean { + String name; + String tagIndex; + String namePinyin; + + CityInfo({ + this.name, + this.tagIndex, + this.namePinyin, + }); + + CityInfo.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'tagIndex': tagIndex, + 'namePinyin': namePinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String getSuspensionTag() => tagIndex; + + @override + String toString() => "CityBean {" + " \"name\":\"" + name + "\"" + '}'; +} + +class CitySelectPage extends StatefulWidget { + final String title; + + CitySelectPage(this.title); + + @override + State createState() { + return new _CitySelectPageState(); + } +} + +class _CitySelectPageState extends State { + List _cityList = List(); + List _hotCityList = List(); + + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + @override + void initState() { + super.initState(); + loadData(); + } + + void loadData() async { + //加载城市列表 + rootBundle.loadString('assets/data/china.json').then((value) { + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + _cityList.add(CityInfo(name: value['name'])); + }); + _handleList(_cityList); + + _hotCityList.add(CityInfo(name: "北京市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "广州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "成都市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "深圳市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "杭州市", tagIndex: "热门")); + _hotCityList.add(CityInfo(name: "武汉市", tagIndex: "热门")); + + setState(() { + _suspensionTag = _hotCityList[0].getSuspensionTag(); + }); + }); + } + + void _handleList(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.getPinyinE(list[i].name); + String tag = pinyin.substring(0, 1).toUpperCase(); + list[i].namePinyin = pinyin; + if (RegExp("[A-Z]").hasMatch(tag)) { + list[i].tagIndex = tag; + } else { + list[i].tagIndex = "#"; + } + } + SuspensionUtil.sortListBySuspensionTag(list); + } + + void _onSusTagChanged(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + ///构建悬停Widget. + Widget _buildSusWidget(String susTag) { + return Container( + height: _suspensionHeight.toDouble(), + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: Text( + '$susTag', + softWrap: false, + style: TextStyle( + fontSize: 14.0, + color: Color(0xff999999), + ), + ), + ); + } + + ///构建列表 item Widget. + Widget _buildListItem(CityInfo model) { + return Column( + children: [ + Offstage( + offstage: !(model.isShowSuspension == true), + child: _buildSusWidget(model.getSuspensionTag()), + ), + SizedBox( + height: _itemHeight.toDouble(), + child: ListTile( + title: Text(model.name), + onTap: () { + LogUtil.e("OnItemClick: $model"); + Navigator.pop(context, model); + }, + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: new AppBar( + title: new Text(widget.title), + centerTitle: true, + ), + body: new Column( + children: [ + Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: Text("当前城市: 成都市"), + ), + Expanded( + flex: 1, + child: new AzListView( + data: _cityList, + topData: _hotCityList, + itemBuilder: (context, model) => _buildListItem(model), + suspensionWidget: _buildSusWidget(_suspensionTag), + isUseRealIndex: true, + itemHeight: _itemHeight, + suspensionHeight: _suspensionHeight, + onSusTagChanged: _onSusTagChanged, + )) + ], + )); + } +} diff --git a/lib/demos/index.dart b/lib/demos/index.dart new file mode 100644 index 0000000..665416f --- /dev/null +++ b/lib/demos/index.dart @@ -0,0 +1 @@ +export 'city_select_page.dart'; diff --git a/lib/main.dart b/lib/main.dart new file mode 100644 index 0000000..9be03b8 --- /dev/null +++ b/lib/main.dart @@ -0,0 +1,140 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_page.dart'; +import 'package:base_app/ui/pages/splash_page.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'blocs/application_bloc.dart'; +import 'blocs/bloc_provider.dart'; +import 'blocs/main_bloc.dart'; +import 'common/common.dart'; +import 'common/global.dart'; +import 'common/sp_helper.dart'; +import 'data/net/dio_util.dart'; +import 'models/common/language_model.dart'; +import 'ui/pages/user/user_login_page.dart'; + +/// APP核心入口文件 +Future main() async { + Global.init(() { + runApp(BlocProvider( + bloc: ApplicationBloc(), + child: BlocProvider(child: MyApp(), bloc: MainBloc()), + )); + }); + // 高德地图配置 + await enableFluttifyLog(false); + await AmapService.init( + iosKey: ' 8fcba5276758c8e0b25c5f263c481db2', + androidKey: 'af843eb87ac0e88dac6c08147579ae0e', + ); +} + +/// MyApp核心入口界面 +class MyApp extends StatefulWidget { + @override + State createState() { + return MyAppState(); + } +} + +class MyAppState extends State { + Locale _locale; // 地区化,国际化用 + Color _themeColor = Colours.app_main; // 主题色 + + @override + void initState() { + super.initState(); + setInitDir(initStorageDir: true); + // setLocalizedSimpleValues(localizedSimpleValues); // 配置简单多语言资源 + setLocalizedValues(localizedValues); // 配置多语言资源 + init(); + } + + void init() { + _init(); + _initListener(); + _loadLocale(); + } + + // 初始化Dio配置 + void _init() { + DioUtil.openDebug(); // 开启调试模式 + Options options = DioUtil.getDefOptions(); + String baseUrl = SpUtil.getString(Constant.key_url); // baseUrl设置 + options.baseUrl = baseUrl; + String token = SpUtil.getString(BaseConstant.keyAppToken); // token + if (ObjectUtil.isNotEmpty(token)) { + Map _headers = new Map(); + _headers["token"] = token; + options.headers = _headers; + } + HttpConfig config = new HttpConfig(options: options); // config + DioUtil().setConfig(config); + } + + /// 初始化监听 + void _initListener() { + final ApplicationBloc bloc = BlocProvider.of(context); + bloc.appEventStream.listen((value) { + // 监听语言变化和专题变化 + _loadLocale(); + }); + } + + /// 初始化应用语言和默认应用主题颜色 + void _loadLocale() { + setState(() { + // 优先读取本地设置 + LanguageModel model = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + if (model != null) { + _locale = new Locale(model.languageCode, model.countryCode); + } else { + _locale = null; + } + // 获取系统颜色,先获取本地设置,默认blue + String _colorKey = SpHelper.getThemeColor(); + if (themeColorMap[_colorKey] != null) + _themeColor = themeColorMap[_colorKey]; + }); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return OKToast( + //toast + child: MaterialApp( + routes: { + //静态路由 + BaseConstant.routeMain: (ctx) => MainPage(), + BaseConstant.routeLogin: (ctx) => UserLoginPage(), + }, + home: new SplashPage(), + theme: ThemeData.light().copyWith( + primaryColor: _themeColor, // 主色:影响标题栏等组件 + accentColor: _themeColor, // 次主色,决定很多组件的背景色 + indicatorColor: Colors.white, //TabBar选中项中指示器颜色 + ), + locale: _locale, + localizationsDelegates: [ + // 本地化代理类 + GlobalMaterialLocalizations.delegate, //提供Material组件库不同语言的字符串值 + GlobalWidgetsLocalizations.delegate, //定义了默认的文本方向 + GlobalCupertinoLocalizations.delegate, // 提供了Cupertinio组件库不同语言的字符串值 + CustomLocalizations.delegate // fluintl 本地化代理 + ], + supportedLocales: CustomLocalizations.supportedLocales, // 支持本地化语言集合 + )); + } +} diff --git a/lib/models/article_model.dart b/lib/models/article_model.dart new file mode 100644 index 0000000..eb018b3 --- /dev/null +++ b/lib/models/article_model.dart @@ -0,0 +1,64 @@ +class ArticleModel { + String id; + int originId; + String title; + String desc; + String author; + String link; + String projectLink; + String envelopePic; + String superChapterName; + int publishTime; + bool collect; + + int type; //1项目,2文章 + bool isShowHeader; + + ArticleModel.fromJson(Map json) + : id = json['id'], + originId = json['originId'], + title = json['title'], + desc = json['desc'], + author = json['author'], + link = json['link'], + projectLink = json['projectLink'], + envelopePic = json['envelopePic'], + superChapterName = json['superChapterName'], + publishTime = json['publishTime'], + collect = json['collect'], + type = json['type']; + + Map toJson() => { + 'id': id, + 'originId': originId, + 'title': title, + 'desc': desc, + 'author': author, + 'link': link, + 'projectLink': projectLink, + 'envelopePic': envelopePic, + 'superChapterName': superChapterName, + 'publishTime': publishTime, + 'collect': collect, + 'type': type, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"id\":$id"); + sb.write(",\"originId\":$originId"); + sb.write(",\"title\":\"$title\""); + sb.write(",\"desc\":\"$desc\""); + sb.write(",\"author\":\"$author\""); + sb.write(",\"link\":\"$link\""); + sb.write(",\"projectLink\":\"$projectLink\""); + sb.write(",\"envelopePic\":\"$envelopePic\""); + sb.write(",\"superChapterName\":\"$superChapterName\""); + sb.write(",\"publishTime\":\"$publishTime\""); + sb.write(",\"collect\":$collect"); + sb.write(",\"type\":$type"); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/banner_model.dart b/lib/models/common/banner_model.dart new file mode 100644 index 0000000..23b128d --- /dev/null +++ b/lib/models/common/banner_model.dart @@ -0,0 +1,31 @@ +/// banner model +class BannerModel { + String title; // 标题 + int id; // id + String url; // 路径 + String imagePath; // 图片路径 + + BannerModel.fromJson(Map json) + : title = json['title'], + id = json['id'], + url = json['url'], + imagePath = json['imagePath']; + + Map toJson() => { + 'title': title, + 'id': id, + 'url': url, + 'imagePath': imagePath, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"id\":$id"); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imagePath\":\"$imagePath\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/component_model.dart b/lib/models/common/component_model.dart new file mode 100644 index 0000000..63bec02 --- /dev/null +++ b/lib/models/common/component_model.dart @@ -0,0 +1,48 @@ +import 'package:flutter/widgets.dart'; + +/// 元素对象,设置列表项等 +class ComponentModel { + String title; // 标题 + String content; // 内容 + String extra; // 其他文字 + String url; // 地址 + String imgUrl; // 图片地址 + int typeId; //类型 + Widget page; // 跳转页面 + + ComponentModel( + {this.title, + this.content, + this.extra, + this.url, + this.imgUrl, + this.typeId, + this.page}); + + ComponentModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + extra = json['extra'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'extra': extra, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write(",\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"extra\":\"$extra\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/language_model.dart b/lib/models/common/language_model.dart new file mode 100644 index 0000000..d18dc4e --- /dev/null +++ b/lib/models/common/language_model.dart @@ -0,0 +1,33 @@ +/// 语言 model +class LanguageModel { + String titleId; // 标题 + String languageCode; // 语言编码 + String countryCode; // 国家编码 + bool isSelected; // 是否选中 + + LanguageModel(this.titleId, this.languageCode, this.countryCode, + {this.isSelected: false}); + + LanguageModel.fromJson(Map json) + : titleId = json['titleId'], + languageCode = json['languageCode'], + countryCode = json['countryCode'], + isSelected = json['isSelected']; + + Map toJson() => { + 'titleId': titleId, + 'languageCode': languageCode, + 'countryCode': countryCode, + 'isSelected': isSelected, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"titleId\":\"$titleId\""); + sb.write(",\"languageCode\":\"$languageCode\""); + sb.write(",\"countryCode\":\"$countryCode\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/splash_model.dart b/lib/models/common/splash_model.dart new file mode 100644 index 0000000..4db354d --- /dev/null +++ b/lib/models/common/splash_model.dart @@ -0,0 +1,33 @@ +/// 闪屏model +class SplashModel { + String title; // 标题 + String content; // 内容 + String url; // 路径 + String imgUrl; // 图片路径 + + SplashModel({this.title, this.content, this.url, this.imgUrl}); + + SplashModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + imgUrl = json['imgUrl']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'imgUrl': imgUrl, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"imgUrl\":\"$imgUrl\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/common/version_model.dart b/lib/models/common/version_model.dart new file mode 100644 index 0000000..6bd3dfe --- /dev/null +++ b/lib/models/common/version_model.dart @@ -0,0 +1,33 @@ +// 版本对象 +class VersionModel { + String title; // 标题 + String content; //新版本说明 + String url; // 版本下载地址 + String version; // 版本号 + + VersionModel({this.title, this.content, this.url, this.version}); + + VersionModel.fromJson(Map json) + : title = json['title'], + content = json['content'], + url = json['url'], + version = json['version']; + + Map toJson() => { + 'title': title, + 'content': content, + 'url': url, + 'version': version, + }; + + @override + String toString() { + StringBuffer sb = new StringBuffer('{'); + sb.write("\"title\":\"$title\""); + sb.write(",\"content\":\"$content\""); + sb.write(",\"url\":\"$url\""); + sb.write(",\"version\":\"$version\""); + sb.write('}'); + return sb.toString(); + } +} diff --git a/lib/models/inspectionModel.dart b/lib/models/inspectionModel.dart new file mode 100644 index 0000000..a4d1873 --- /dev/null +++ b/lib/models/inspectionModel.dart @@ -0,0 +1,78 @@ +// 巡检的model +import 'dart:math'; +import 'dart:convert' as convert; +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; + +class InspectionModel { + String id; //id + String name; // 巡检标签 + String startTime; //开始事件 + String endTime; // 结束时间 + String date; // 日期 + double startLng; // 开始经度 + double startLat; // 开始纬度 + double endLng; // 结束经度 + double endLat; // 结束维度 + // List startPosition; // 开始位置 + // List endPosition; // 结束位置 + List routes; // 路线 + String user; // 巡检人 + + InspectionModel(id, name, startTime,endTime,startLng,startLat,endLng,endLat,routes,tasks,user){ + // 生成随机主键 + if(id==null){ + var rng = new Random(); + this.id = DateUtil.getNowDateMs().toString()+rng.nextInt(999).toRadixString(3); + }else{ + this.id = id; + } + this.name = name; + this.startTime = startTime; + this.endTime = endTime; + this.startLng = startLng; + this.startLat = startLat; + this.endLng = endLng; + this.endLat = endLat; + // this.startPosition = startPosition; + // this.endPosition = endPosition; + this.routes = routes; + this.date = DateUtil.formatDateStr(startTime,format:'yyyy年MM月dd日'); + this.user = user; + + } + + InspectionModel.fromJson(Map json){ + startTime= json['startTime']; + endTime = json['endTime']; + startLng = json['startLng']; + startLat = json['startLat']; + endLng = json['endLng']; + endLat = json['endLat']; + routes = convert.jsonDecode(json['routes']); + id = json['id']; + name = json['name']; + date = json['date']; + user = json['user']; + } + + Map toJson() => { + 'startTime': startTime, + 'endTime': endTime, + 'startLng': startLng, + 'startLat': startLat, + 'endLng': endLng, + 'endLat':endLat, + 'routes': convert.jsonEncode(routes), + 'id' : id, + 'name' : name, + 'user' : user, + 'date' : date + }; + + FormData toFormData(){ + Map jsonMap = toJson(); + print(jsonMap); + return FormData.from(jsonMap); + } +} diff --git a/lib/models/models.dart b/lib/models/models.dart new file mode 100644 index 0000000..f6fc6cd --- /dev/null +++ b/lib/models/models.dart @@ -0,0 +1,4 @@ +export 'common/banner_model.dart'; +export 'common/language_model.dart'; +export 'common/splash_model.dart'; +export 'article_model.dart'; diff --git a/lib/res/colors.dart b/lib/res/colors.dart new file mode 100644 index 0000000..b211165 --- /dev/null +++ b/lib/res/colors.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; + +class Colours { + static const Color app_main = Color(0xff147de8); + + static const Color transparent_80 = Color(0x80000000); // + + static const Color text_dark = Color(0xFF333333); + static const Color text_normal = Color(0xFF666666); + static const Color text_gray = Color(0xFF999999); + + static const Color blue_light = Color(0xff14bfff); + + static const Color divider = Color(0xffe5e5e5); + + static const Color gray_33 = Color(0xFF333333); //51 + static const Color gray_66 = Color(0xFF666666); //102 + static const Color gray_99 = Color(0xFF999999); //153 + static const Color common_orange = Color(0XFFFC9153); //252 145 83 + static const Color gray_ef = Color(0XFFEFEFEF); //153 + + static const Color gray_f0 = Color(0xfff0f0f0); // + static const Color gray_f5 = Color(0xfff5f5f5); // + static const Color gray_cc = Color(0xffcccccc); // + static const Color gray_ce = Color(0xffcecece); // + static const Color green_1 = Color(0xff009688); // + static const Color green_62 = Color(0xff626262); // + static const Color green_e5 = Color(0xffe5e5e5); // + + static const Color green_de = Color(0xffdedede); +} + +// 头像颜色 +Map circleAvatarMap = { + 'A': Colors.blueAccent, + 'B': Colors.blue, + 'C': Colors.cyan, + 'D': Colors.deepPurple, + 'E': Colors.deepPurpleAccent, + 'F': Colors.blue, + 'G': Colors.green, + 'H': Colors.lightBlue, + 'I': Colors.indigo, + 'J': Colors.blue, + 'K': Colors.blue, + 'L': Colors.lightGreen, + 'M': Colors.blue, + 'N': Colors.brown, + 'O': Colors.orange, + 'P': Colors.purple, + 'Q': Colors.black, + 'R': Colors.red, + 'S': Colors.blue, + 'T': Colors.teal, + 'U': Colors.purpleAccent, + 'V': Colors.black, + 'W': Colors.brown, + 'X': Colors.blue, + 'Y': Colors.yellow, + 'Z': Colors.grey, + '#': Colors.blue, +}; + +// 主题色Map +Map themeColorMap = { + 'gray': Colours.gray_33, + 'blue': Colours.app_main, + 'blueAccent': Colors.blueAccent, + 'cyan': Colors.cyan, + 'deepPurple': Colors.deepPurple, + 'deepPurpleAccent': Colors.deepPurpleAccent, + 'deepOrange': Colors.deepOrange, + 'green': Colors.green, + 'indigo': Colors.indigo, + 'indigoAccent': Colors.indigoAccent, + 'orange': Colors.orange, + 'purple': Colors.purple, + 'pink': Colors.pink, + 'red': Colors.red, + 'teal': Colors.teal, + 'black': Colors.black, +}; diff --git a/lib/res/dimens.dart b/lib/res/dimens.dart new file mode 100644 index 0000000..4bd8728 --- /dev/null +++ b/lib/res/dimens.dart @@ -0,0 +1,15 @@ +class Dimens { + static const double font_sp10 = 10; + static const double font_sp12 = 12; + static const double font_sp14 = 14; + static const double font_sp16 = 16; + static const double font_sp18 = 18; + + static const double gap_dp5 = 5; + static const double gap_dp10 = 10; + static const double gap_dp12 = 12; + static const double gap_dp15 = 15; + static const double gap_dp16 = 16; + static const double gap_dp20 = 20; + static const double gap_dp25 = 25; +} diff --git a/lib/res/index.dart b/lib/res/index.dart new file mode 100644 index 0000000..9b18af8 --- /dev/null +++ b/lib/res/index.dart @@ -0,0 +1,4 @@ +export 'colors.dart'; +export 'dimens.dart'; +export 'strings.dart'; +export 'styles.dart'; diff --git a/lib/res/strings.dart b/lib/res/strings.dart new file mode 100644 index 0000000..6a1b7c8 --- /dev/null +++ b/lib/res/strings.dart @@ -0,0 +1,246 @@ +/// 创建多语言资源字符串id管理类StringIds 和 多语言资源Map + +/// 多语言资源id管理类 +class Ids { + static const String server_url_set = 'server_url_set'; + static const String titleHome = 'title_home'; + static const String titleRepos = 'title_repos'; + static const String titleEvents = 'title_events'; + static const String titleList = 'title_list'; + static const String titleVersion = 'title_version'; + + static const String titleBookmarks = 'title_bookmarks'; + static const String titleCollection = 'title_collection'; + static const String titleSetting = 'title_setting'; + static const String titleAbout = 'title_about'; + static const String titleHelp = 'title_help'; + static const String titleShare = 'title_share'; + static const String titleSignOut = 'title_signout'; + static const String titleLanguage = 'title_language'; + static const String titleTheme = 'title_theme'; + static const String titleAuthor = 'title_author'; + static const String titleOther = 'title_other'; + + static const String languageAuto = 'language_auto'; + static const String languageZH = 'language_zh'; + static const String languageTW = 'language_tw'; + static const String languageHK = 'language_hk'; + static const String languageEN = 'language_en'; + + static const String save = 'save'; + static const String more = 'more'; + + static const String recRepos = 'rec_repos'; + static const String recWxArticle = 'rec_wxarticle'; + + static const String titleReposTree = 'title_repos_tree'; + static const String titleWxArticleTree = 'title_wxarticle_tree'; + static const String titleSystemTree = 'title_list_tree'; + + static const String user_name = 'user_name'; + static const String user_pwd = 'user_pwd'; + static const String user_re_pwd = 'user_re_pwd'; + static const String user_login = 'user_login'; + static const String user_register = 'user_register'; + static const String user_forget_pwd = 'user_forget_pwd'; + static const String user_new_user_hint = 'user_new_user_hint'; + + static const String confirm = 'confirm'; + static const String cancel = 'cancel'; + + static const String jump_count = 'jump_count'; + + static const String hint_new_version = 'hint_new_version'; // 有最新版 + static const String hint_is_new = 'hint_is_new'; // 已是最新版 + static const String hint_quit = 'hint_quit'; // 确定退出吗? +} + +// 简单多语言资源 +Map> localizedSimpleValues = { + 'en': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: '列表示例', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.languageAuto: 'Auto', + }, + 'zh': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表示例', + Ids.titleBookmarks: '书签', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + }, +}; + +// 多语言资源 +Map>> localizedValues = { + 'en': { + 'US': { + Ids.titleHome: 'Home', + Ids.titleRepos: 'Repos', + Ids.titleEvents: 'Events', + Ids.titleList: 'List', + Ids.titleBookmarks: 'Bookmarks', + Ids.titleCollection: 'Collection', + Ids.titleSetting: 'Setting', + Ids.titleAbout: 'About', + Ids.titleHelp: 'Help', + Ids.titleShare: 'Share', + Ids.titleSignOut: 'Sign Out', + Ids.titleLanguage: 'Language', + Ids.titleVersion: 'Version update', + Ids.languageAuto: 'Auto', + Ids.save: 'Save', + Ids.more: 'More', + Ids.recRepos: 'Reco Repos', + Ids.recWxArticle: 'Reco WxArticle', + Ids.titleReposTree: 'Repos Tree', + Ids.titleWxArticleTree: 'Wx Article', + Ids.titleTheme: 'Theme', + Ids.server_url_set: 'server setting', + Ids.user_name: 'user name', + Ids.user_pwd: 'password', + Ids.user_re_pwd: 'confirm password', + Ids.user_login: 'Login', + Ids.user_register: 'Register', + Ids.user_forget_pwd: 'Forget the password?', + Ids.user_new_user_hint: 'New users? ', + Ids.confirm: 'Confirm', + Ids.cancel: 'Cancel', + Ids.jump_count: 'Jump %\$0\$s', + Ids.hint_new_version: 'new version comming!', + Ids.hint_is_new: 'The latest version', + Ids.hint_quit: 'Are you sure to quit the app?' + } + }, + 'zh': { + 'CN': { + Ids.titleHome: '主页', + Ids.titleRepos: '项目', + Ids.titleEvents: '动态', + Ids.titleList: '列表', + Ids.titleBookmarks: '书签', + Ids.titleCollection: '收藏', + Ids.titleSetting: '设置', + Ids.titleAbout: '关于', + Ids.titleHelp: '帮助', + Ids.titleShare: '分享', + Ids.titleSignOut: '退出', + Ids.titleVersion: '版本更新', + Ids.titleLanguage: '多语言', + Ids.languageAuto: '跟随系统', + Ids.languageZH: '简体中文', + Ids.languageTW: '繁體中文(台灣)', + Ids.languageHK: '繁體中文(香港)', + Ids.languageEN: 'English', + Ids.save: '保存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主题', + Ids.server_url_set: '服务器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本啦!快来体验', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'HK': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '列表', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleHelp: '幫助', + Ids.titleShare: '分享', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + }, + 'TW': { + Ids.titleHome: '主頁', + Ids.titleRepos: '項目', + Ids.titleEvents: '動態', + Ids.titleList: '體系', + Ids.titleBookmarks: '書簽', + Ids.titleCollection: '收藏', + Ids.titleSetting: '設置', + Ids.titleAbout: '關於', + Ids.titleShare: '分享', + Ids.titleHelp: '幫助', + Ids.titleSignOut: '註銷', + Ids.titleLanguage: '語言', + Ids.titleVersion: '版本更新', + Ids.languageAuto: '與系統同步', + Ids.save: '儲存', + Ids.more: '更多', + Ids.recRepos: '推荐项目', + Ids.recWxArticle: '推荐公众号', + Ids.titleReposTree: '项目分类', + Ids.titleWxArticleTree: '公众号', + Ids.titleTheme: '主題', + Ids.server_url_set: '服務器配置', + Ids.user_name: '用户名', + Ids.user_pwd: '密码', + Ids.user_re_pwd: '确认密码', + Ids.user_login: '登录', + Ids.user_register: '注册', + Ids.user_forget_pwd: '忘记密码?', + Ids.user_new_user_hint: '新用户?', + Ids.confirm: '确认', + Ids.cancel: '取消', + Ids.jump_count: '跳过 %\$0\$s', + Ids.hint_new_version: '有新版本了!快來體驗', + Ids.hint_is_new: '已是最新版本', + Ids.hint_quit: '确定退出吗?' + } + } +}; diff --git a/lib/res/styles.dart b/lib/res/styles.dart new file mode 100644 index 0000000..8f4a8f8 --- /dev/null +++ b/lib/res/styles.dart @@ -0,0 +1,44 @@ +import 'package:base_app/res/dimens.dart'; +import 'package:flutter/widgets.dart'; +import 'package:base_app/res/colors.dart'; + +class TextStyles { + static TextStyle listTitle = TextStyle( + fontSize: Dimens.font_sp16, + color: Colours.text_dark, + fontWeight: FontWeight.bold, + ); + static TextStyle listContent = TextStyle( + fontSize: Dimens.font_sp14, + color: Colours.text_normal, + ); + static TextStyle listExtra = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_gray, + ); + static TextStyle listExtra2 = TextStyle( + fontSize: Dimens.font_sp12, + color: Colours.text_normal, + ); +} + +class Decorations { + static Decoration bottom = BoxDecoration( + border: Border(bottom: BorderSide(width: 0.33, color: Colours.divider))); +} + +/// 间隔 +class Gaps { + /// 水平间隔 + static Widget hGap5 = new SizedBox(width: Dimens.gap_dp5); + static Widget hGap10 = new SizedBox(width: Dimens.gap_dp10); + static Widget hGap15 = new SizedBox(width: Dimens.gap_dp15); + static Widget hGap20 = new SizedBox(width: Dimens.gap_dp20); + + /// 垂直间隔 + static Widget vGap5 = new SizedBox(height: Dimens.gap_dp5); + static Widget vGap10 = new SizedBox(height: Dimens.gap_dp10); + static Widget vGap15 = new SizedBox(height: Dimens.gap_dp15); + static Widget vGap20 = new SizedBox(height: Dimens.gap_dp20); + static Widget vGap25 = new SizedBox(height: Dimens.gap_dp25); +} diff --git a/lib/ui/pages/common/about_page.dart b/lib/ui/pages/common/about_page.dart new file mode 100644 index 0000000..e909544 --- /dev/null +++ b/lib/ui/pages/common/about_page.dart @@ -0,0 +1,127 @@ +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/blocs/main_bloc.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/common/help_page.dart'; +import 'package:base_app/ui/widgets/common/com_item.dart'; +import 'package:base_app/ui/widgets/common/dialog/upgrade_dialog_widget.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +/// 关于页面: 版本更新,帮助等 +class AboutPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + final MainBloc bloc = BlocProvider.of(context); + // 帮助 + ComponentModel help = ComponentModel( + title: IntlUtil.getString(context, Ids.titleHelp), page: HelpPage()); + + return Scaffold( + appBar: AppBar( + title: Text(IntlUtil.getString(context, Ids.titleAbout)), + centerTitle: true, + ), + body: ListView( + children: [ + // logo,app名称和版本号展示 + Container( + height: 160.0, + alignment: Alignment.center, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Card( + color: Theme.of(context).primaryColor, + elevation: 0.0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6.0))), + child: Image.asset( + Utils.getImgPath('logo'), + width: 72.0, + fit: BoxFit.fill, + height: 72.0, + ), + ), + Gaps.vGap5, + Text( + AppConfig.appName + ' ' + AppConfig.version, + style: TextStyle(color: Colours.gray_99, fontSize: 14.0), + ) + ], + ), + decoration: BoxDecoration( + color: Colors.white, + border: Border.all(width: 0.33, color: Colours.divider))), + // 帮助 + ComArrowItem(help), + // 版本更新检测,versionStream + StreamBuilder( + stream: bloc.versionStream, + builder: + (BuildContext context, AsyncSnapshot snapshot) { + VersionModel model = snapshot.data; + return Container( + child: Material( + color: Colors.white, + child: ListTile( + onTap: () { + // 点击监测版本 + if (model == null) { + bloc.getVersion(); + } else { + if (Utils.getUpdateStatus(model.version) > 0) { + //NavigatorUtil.launchInBrowser(model.url, title: model.title); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => UpgradeDialog( + versionModel: model, + appId: AppConfig.appId, + ), + ); + } + } + }, + title: + Text(IntlUtil.getString(context, Ids.titleVersion)), + //dense: true, + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + model == null + ? '' + : (Utils.getUpdateStatus(model.version) == 0 + ? IntlUtil.getString( + context, Ids.hint_is_new) + : IntlUtil.getString( + context, Ids.hint_new_version)), + style: TextStyle( + color: (model != null && + Utils.getUpdateStatus(model.version) != + 0) + ? Colors.red + : Colors.grey, + fontSize: 14.0), + ), + Icon( + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + }), + ], + ), + ); + } +} diff --git a/lib/ui/pages/common/help_page.dart b/lib/ui/pages/common/help_page.dart new file mode 100644 index 0000000..383302d --- /dev/null +++ b/lib/ui/pages/common/help_page.dart @@ -0,0 +1,15 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HelpPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text(IntlUtil.getString(context, Ids.titleHelp)), + centerTitle: true, + ), + body: new Container(child: Text("帮助页面"))); + } +} diff --git a/lib/ui/pages/common/language_page.dart b/lib/ui/pages/common/language_page.dart new file mode 100644 index 0000000..a75f2b4 --- /dev/null +++ b/lib/ui/pages/common/language_page.dart @@ -0,0 +1,126 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +/// 选择语言页面 +class LanguagePage extends StatefulWidget { + @override + State createState() { + return _LanguagePageState(); + } +} + +class _LanguagePageState extends State { + // 多语言列表 + List _list = new List(); + // 当前语言 + LanguageModel _currentLanguage; + + @override + void initState() { + super.initState(); + + // 语言列表 + _list.add(LanguageModel(Ids.languageAuto, '', '')); + _list.add(LanguageModel(Ids.languageZH, 'zh', 'CH')); + _list.add(LanguageModel(Ids.languageTW, 'zh', 'TW')); + _list.add(LanguageModel(Ids.languageHK, 'zh', 'HK')); + _list.add(LanguageModel(Ids.languageEN, 'en', 'US')); + + // 当前语言,否则默认列表第一个(跟随系统) + _currentLanguage = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + + if (ObjectUtil.isEmpty(_currentLanguage)) { + _currentLanguage = _list[0]; + } + + _updateData(); + } + + void _updateData() { + LogUtil.e('currentLanguage: ' + _currentLanguage.toString()); + String language = _currentLanguage.countryCode; + for (int i = 0, length = _list.length; i < length; i++) { + _list[i].isSelected = (_list[i].countryCode == language); + } + } + + @override + Widget build(BuildContext context) { + // application bloc + final ApplicationBloc bloc = BlocProvider.of(context); + + return new Scaffold( + appBar: new AppBar( + title: new Text( + IntlUtil.getString(context, Ids.titleLanguage), + // style: new TextStyle(fontSize: 16.0), + ), + actions: [ + // 保存按钮 + new Padding( + padding: EdgeInsets.all(12.0), + child: new SizedBox( + width: 64.0, + child: new RaisedButton( + textColor: Colors.white, + color: Colours.app_main, + child: Text( + IntlUtil.getString(context, Ids.save), + style: new TextStyle(fontSize: 14.0), + ), + onPressed: () { + // 保存当前语言,并通知给整个app + SpUtil.putObject( + Constant.keyLanguage, + ObjectUtil.isEmpty(_currentLanguage.languageCode) + ? null + : _currentLanguage); + bloc.sendAppEvent(Constant.type_sys_update); + Navigator.pop(context); + }, + ), + ), + ), + ], + ), + // 语言列表 + body: new ListView.builder( + itemCount: _list.length, + itemBuilder: (BuildContext context, int index) { + LanguageModel model = _list[index]; + return new ListTile( + title: new Text( + (model.titleId == Ids.languageAuto + ? IntlUtil.getString(context, model.titleId) + : IntlUtil.getString(context, model.titleId, + languageCode: 'zh', countryCode: 'CH')), + style: new TextStyle(fontSize: 13.0), + ), + trailing: new Radio( + value: true, + groupValue: model.isSelected == true, + // activeColor: Colors.indigoAccent, + onChanged: (value) { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }), + onTap: () { + setState(() { + _currentLanguage = model; + _updateData(); + }); + }, + ); + }), + ); + } +} diff --git a/lib/ui/pages/common/setting_page.dart b/lib/ui/pages/common/setting_page.dart new file mode 100644 index 0000000..571c8fd --- /dev/null +++ b/lib/ui/pages/common/setting_page.dart @@ -0,0 +1,104 @@ +import 'package:base_app/blocs/application_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/language_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'language_page.dart'; + +/// 设置页面 +class SettingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + LogUtil.e("SettingPage build......"); + final ApplicationBloc bloc = BlocProvider.of(context); + LanguageModel languageModel = + SpUtil.getObj(Constant.keyLanguage, (v) => LanguageModel.fromJson(v)); + return new Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, Ids.titleSetting), + ), + centerTitle: true, + ), + body: ListView( + children: [ + new ExpansionTile( + title: new Row( + children: [ + Icon( + Icons.color_lens, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleTheme), + ), + ) + ], + ), + children: [ + new Wrap( + children: themeColorMap.keys.map((String key) { + Color value = themeColorMap[key]; + return new InkWell( + onTap: () { + SpUtil.putString(Constant.key_theme_color, key); + bloc.sendAppEvent(Constant.type_sys_update); + }, + child: new Container( + margin: EdgeInsets.all(5.0), + width: 36.0, + height: 36.0, + color: value, + ), + ); + }).toList(), + ) + ], + ), + new ListTile( + title: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + ), + Padding( + padding: EdgeInsets.only(left: 10.0), + child: Text( + IntlUtil.getString(context, Ids.titleLanguage), + ), + ) + ], + ), + trailing: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + languageModel == null + ? IntlUtil.getString(context, Ids.languageAuto) + : IntlUtil.getString(context, languageModel.titleId, + languageCode: 'zh', countryCode: 'CH'), + style: TextStyle( + fontSize: 14.0, + color: Colours.gray_99, + )), + Icon(Icons.keyboard_arrow_right) + ], + ), + onTap: () { + NavigatorUtil.pushPage(context, LanguagePage(), + pageName: Ids.titleLanguage); + }, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/demo_tab_page.dart b/lib/ui/pages/demo/demo_tab_page.dart new file mode 100644 index 0000000..722c64e --- /dev/null +++ b/lib/ui/pages/demo/demo_tab_page.dart @@ -0,0 +1,51 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page.dart'; +import 'package:base_app/ui/pages/demo/tabPage/static_tab_page2.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class DemoTabPage extends StatelessWidget { + final String labelId; + + const DemoTabPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget tab1 = new LargeButton( + text: '静态tab1', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + Widget tab2 = new LargeButton( + text: '静态tab2', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage( + context, + new StaticTabPage2( + labelId: Ids.titleList, + titleId: Ids.titleList, + )); + // RouteUtil.pushNamed(context, 'route_setting'); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, tab1, tab2], + ), + ); + } +} diff --git a/lib/ui/pages/demo/iconPage/sample_icon_page.dart b/lib/ui/pages/demo/iconPage/sample_icon_page.dart new file mode 100644 index 0000000..d17017c --- /dev/null +++ b/lib/ui/pages/demo/iconPage/sample_icon_page.dart @@ -0,0 +1,84 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SampleIconPage extends StatelessWidget { + final String labelId; + + const SampleIconPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // iconFont示例 + Widget iconFontsWidget = new Column(children: [ + Text("单色图标,可设定颜色"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + IconfontIcon( + iconData: IconfontIcons.icon_add, + color: Colors.blueAccent, + size: 25, + ), + IconfontIcon(iconData: IconfontIcons.icon_addmessage), + IconfontIcon(iconData: IconfontIcons.icon_addperson), + IconfontIcon(iconData: IconfontIcons.icon_addresslist), + IconfontIcon(iconData: IconfontIcons.icon_affiliations_li), + IconfontIcon(iconData: IconfontIcons.icon_airplay), + IconfontIcon(iconData: IconfontIcons.icon_attestation), + IconfontIcon(iconData: IconfontIcons.icon_boss), + IconfontIcon(iconData: IconfontIcons.icon_calendar), + IconfontIcon(iconData: IconfontIcons.icon_camera), + IconfontIcon(iconData: IconfontIcons.icon_certificate_fil), + IconfontIcon(iconData: IconfontIcons.icon_coinpurse_line), + IconfontIcon(iconData: IconfontIcons.icon_compile), + IconfontIcon(iconData: IconfontIcons.icon_collect) + ], + ) + ]); + + Widget imageIconWidget = new Column(children: [ + Text("图片图标"), + Wrap( + direction: Axis.horizontal, + alignment: WrapAlignment.start, + children: [ + imageIcon(icon: 'camera'), + imageIcon(icon: 'card'), + imageIcon(icon: 'global'), + imageIcon(icon: 'image'), + imageIcon(icon: 'magic'), + imageIcon(icon: 'position'), + imageIcon(icon: 'scan'), + imageIcon(icon: 'setting'), + imageIcon(icon: 'text'), + imageIcon(icon: 'warning'), + ], + ) + ]); + + // 全局 + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text("icon示例"), + centerTitle: true, // 标题居中 + ), + body: SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + Container(margin: EdgeInsets.all(20), child: iconFontsWidget), + Container(margin: EdgeInsets.all(20), child: imageIconWidget) + ], + ), + )); + } +} diff --git a/lib/ui/pages/demo/list_page.dart b/lib/ui/pages/demo/list_page.dart new file mode 100644 index 0000000..4959c06 --- /dev/null +++ b/lib/ui/pages/demo/list_page.dart @@ -0,0 +1,138 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_provider.dart'; +import 'package:base_app/models/models.dart'; +import 'package:base_app/ui/widgets/common/list/article_item.dart'; +import 'package:base_app/ui/widgets/common/list/header_item.dart'; +import 'package:base_app/ui/widgets/common/list/refresh_scaffold.dart'; +import 'package:base_app/ui/widgets/common/progress_view_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 简洁主页面 +class ListPage extends StatelessWidget { + final String labelId; + + const ListPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + // 图片轮播 + Widget buildBanner(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + return new AspectRatio( + aspectRatio: 16.0 / 9.0, + // Swiper 控件 + child: Swiper( + indicatorAlignment: AlignmentDirectional.topEnd, + circular: true, + interval: const Duration(seconds: 5), + indicator: NumberSwiperIndicator(), + children: list.map((model) { + return new InkWell( + onTap: () { + LogUtil.e("BannerModel: " + model.toString()); + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + }, + child: new CachedNetworkImage( + fit: BoxFit.fill, + imageUrl: model.imagePath, + placeholder: (context, url) => new ProgressView(), + errorWidget: (context, url, error) => new Icon(Icons.error), + ), + ); + }).toList(), + ), + ); + } + + // 文章列表 + Widget buildArticleList(BuildContext context, List list) { + if (ObjectUtil.isEmpty(list)) { + return new Container(height: 0.0); + } + // 每个article, 子元素 + List _children = list.map((model) { + return new ArticleItem( + model, + ); + }).toList(); + List children = new List(); + children.add(new HeaderItem( + // 列表的头 + leftIcon: Icons.book, + title: "推荐项目", + onTap: () { + showToast("点击推荐项目"); + }, + )); + children.addAll(_children); + return new Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: children, + ); + } + + @override + Widget build(BuildContext context) { + // bloc + final ListBloc bloc = BlocProvider.of(context); + RefreshController _controller = new RefreshController(); + + // 获取数据 + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + bloc.getData(labelId: labelId); + }); + + // 全局 + return new StreamBuilder( + stream: bloc.bannerStream, // banner stream + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + return new RefreshScaffold( + labelId: labelId, + loadStatus: Utils.getLoadStatus(snapshot.hasError, snapshot.data), + controller: _controller, + enablePullUp: false, + onRefresh: ({bool isReload}) { + return bloc.onRefresh(labelId: labelId); + }, + child: new ListView( + children: [ + buildBanner(context, snapshot.data), // 轮播广告banner + // 文章列表 + new StreamBuilder( + stream: bloc.articleStream, + builder: (BuildContext context, + AsyncSnapshot> snapshot) { + return buildArticleList(context, snapshot.data); + }) + ], + ), + ); + }); + } +} + +/// 滑动的数字指示器 +class NumberSwiperIndicator extends SwiperIndicator { + @override + Widget build(BuildContext context, int index, int itemCount) { + return Container( + decoration: BoxDecoration( + color: Colors.black45, borderRadius: BorderRadius.circular(20.0)), + margin: EdgeInsets.only(top: 10.0, right: 5.0), + padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 2.0), + child: Text("${++index}/$itemCount", + style: TextStyle(color: Colors.white70, fontSize: 11.0)), + ); + } +} diff --git a/lib/ui/pages/demo/mapPage/create_map_page.dart b/lib/ui/pages/demo/mapPage/create_map_page.dart new file mode 100644 index 0000000..a7bc528 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/create_map_page.dart @@ -0,0 +1,138 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon = AssetImage('assets/images/qidian.png'); + +class CreateMapPage extends StatefulWidget { + @override + _CreateMapPageState createState() => _CreateMapPageState(); +} + +class _CreateMapPageState extends State { + AmapController _controller; // 地图controller + bool showTraffic = false; + Map mapTypeList = { + 'satellite': MapType.Satellite, + 'standard': MapType.Standard, + 'navi': MapType.Navi, + 'bus': MapType.Bus, + 'night': MapType.Night + }; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('自定义地图')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 显示/隐藏路况信息 ", + radius: 8, + onPressed: () { + showTraffic = !showTraffic; + _controller?.showTraffic(showTraffic); + }, + ), + new RoundButton( + text: " 卫星 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['satellite']); + }, + ), + new RoundButton( + text: " 矢量 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['standard']); + }, + ), + new RoundButton( + text: " 公交 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['bus']); + }, + ), + new RoundButton( + text: " 暗黑 ", + radius: 8, + onPressed: () { + _controller.setMapType(mapTypeList['night']); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/mapPage/draw_map_page.dart b/lib/ui/pages/demo/mapPage/draw_map_page.dart new file mode 100644 index 0000000..efe89a2 --- /dev/null +++ b/lib/ui/pages/demo/mapPage/draw_map_page.dart @@ -0,0 +1,213 @@ +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/utils/permission_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +final _assetsIcon1 = AssetImage('assets/images/qidian.png'); + +class DrawMapPage extends StatefulWidget { + @override + _DrawMapPageState createState() => _DrawMapPageState(); +} + +class _DrawMapPageState extends State with NextLatLng { + AmapController _controller; // 地图controller + List _markers = []; // markers + List _circleList = []; //circleList + List _polygonList = []; + Polyline _currentPolyline; + List _pointList = []; + + @override + Widget build(BuildContext context) { + // 功能栏Widget + Widget functionBar = Container( + child: new Column( + children: [ + new FloatingActionButton( + // 回到当前位置按钮 + mini: true, + heroTag: 'gps_setting', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.gps_fixed, size: 26, color: Colours.gray_66), + onPressed: () async { + final latLng = await _controller?.getLocation(); + final lat = latLng.latitude; + final lng = latLng.longitude; + showToast("$lng,$lat"); + _controller.setCenterCoordinate(latLng); + }), + new FloatingActionButton( + // 清屏 + mini: true, + heroTag: 'refreshData', + shape: new CircleBorder(), + backgroundColor: Colors.white, + child: Icon(Icons.delete, size: 26, color: Colours.gray_66), + onPressed: () async { + await _controller.clearMarkers(_markers); + if (_circleList.isNotEmpty) { + await _circleList.first.remove(); + _circleList.removeAt(0); + } + if (_polygonList.isNotEmpty) { + await _polygonList.first.remove(); + _polygonList.removeAt(0); + } + _currentPolyline?.remove(); + }), + ], + )); + return Scaffold( + appBar: AppBar(title: const Text('地图绘制示例')), + body: new Stack(children: [ + Container( + height: double.infinity, + width: double.infinity, + color: Colors.white24, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: [ + Expanded( + child: Container( + child: AmapView( + showScaleControl: false, // 是否显示比例尺 + showZoomControl: false, // 是否显示缩放控件 + rotateGestureEnabled: false, // 是否允许旋转 + tiltGestureEnabled: false, + onMapCreated: (controller) async { + print("onMapCreate"); + if (await reqPositionPermission()) { + // await controller.showMyLocation(MyLocationOption(show: true)); + _controller = controller; + await _controller?.showMyLocation(MyLocationOption( + myLocationType: MyLocationType.Locate, // 定位模式 + interval: Duration(seconds: 3) // 定位间隔时间 + )); + } + }, + ), + ), + ), + Container( + height: 55.0, + margin: EdgeInsets.all(10), + width: double.infinity, + color: Colors.white, + padding: EdgeInsets.symmetric(horizontal: 8), + child: new Row( + children: [ + new RoundButton( + text: " 绘制点 ", + radius: 8, + onPressed: () async { + final marker = await _controller?.addMarker( + MarkerOption( + latLng: getNextLatLng(), + title: '北京${random.nextDouble()}', + snippet: '描述${random.nextDouble()}', + iconProvider: _assetsIcon1, + infoWindowEnabled: true, + object: '自定义数据${random.nextDouble()}', + ), + ); + // 自定义弹窗 + await _controller + ?.setMarkerClickedListener((marker) async { + await _controller.showCustomInfoWindow( + marker, + Container( + width: 128, + height: 122, + padding: EdgeInsets.all(10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + ), + child: Text(await marker.title), + ), + ); + }); + _markers.add(marker); + }, + ), + new RoundButton( + text: " 绘制圆 ", + margin: EdgeInsets.symmetric(horizontal: 5), + radius: 8, + onPressed: () async { + final circle = + await _controller?.addCircle(CircleOption( + center: LatLng(39.999391, 116.135972), + radius: 10000, + width: 10, + strokeColor: Colors.green, + )); + _circleList.add(circle); + }, + ), + new RoundButton( + text: " 绘制多边形 ", + radius: 8, + onPressed: () async { + final polygon = + await _controller?.addPolygon(PolygonOption( + latLngList: [ + LatLng(39.999391, 116.135972), + LatLng(39.898323, 116.057694), + LatLng(39.900430, 116.265061), + LatLng(39.955192, 116.140092), + ], + width: 10, + strokeColor: Colors.green, + )); + _polygonList.add(polygon); + }, + ), + new RoundButton( + text: " 曲线 ", + radius: 8, + margin: EdgeInsets.symmetric(horizontal: 5), + onPressed: () async { + _pointList = [ + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + getNextLatLng(), + ]; + _currentPolyline = + await _controller?.addPolyline(PolylineOption( + latLngList: _pointList, + width: 10, + strokeColor: Colors.green, + )); + }, + ), + new RoundButton( + text: " 地图缩放 ", + radius: 8, + onPressed: () async { + _controller?.zoomToSpan( + _pointList, + padding: EdgeInsets.only(top: 100), + ); + }, + ), + ], + ), + ) + ]), + ), + new Positioned( + // 左上角功能栏 + left: 10.0, + top: 60.0, + child: functionBar), + ])); + } +} diff --git a/lib/ui/pages/demo/map_page.dart b/lib/ui/pages/demo/map_page.dart new file mode 100644 index 0000000..08a230f --- /dev/null +++ b/lib/ui/pages/demo/map_page.dart @@ -0,0 +1,41 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/mapPage/create_map_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'mapPage/draw_map_page.dart'; + +/// 简洁主页面 +class MapPage extends StatelessWidget { + final String labelId; + + const MapPage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget createMap = new LargeButton( + text: '创建地图', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new CreateMapPage()); + }); + // 系统设置 + Widget drawMap = new LargeButton( + text: '地图绘制', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new DrawMapPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [Gaps.vGap15, createMap, drawMap], + ), + ); + } +} diff --git a/lib/ui/pages/demo/simple_page.dart b/lib/ui/pages/demo/simple_page.dart new file mode 100644 index 0000000..ca7114f --- /dev/null +++ b/lib/ui/pages/demo/simple_page.dart @@ -0,0 +1,35 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/iconPage/sample_icon_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +/// 简洁主页面 +class SimplePage extends StatelessWidget { + final String labelId; + + const SimplePage({Key key, this.labelId}) : super(key: key); // 页面的labelId + + @override + Widget build(BuildContext context) { + // 系统设置 + Widget systemSettingSection = new LargeButton( + text: 'icon示例', + iconPath: "", + onTap: () { + NavigatorUtil.pushPage(context, new SampleIconPage()); + }); + // 全局 + return new SingleChildScrollView( + physics: BouncingScrollPhysics(), + child: new Column( + children: [ + Gaps.vGap15, + systemSettingSection, + ], + ), + ); + } +} diff --git a/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart new file mode 100644 index 0000000..6600cfa --- /dev/null +++ b/lib/ui/pages/demo/tabPage/dynamic_tab_page copy.dart @@ -0,0 +1,79 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class DynamicTabPage extends StatefulWidget { + const DynamicTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new DynamicTabPageState(); + } +} + +class DynamicTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page.dart b/lib/ui/pages/demo/tabPage/static_tab_page.dart new file mode 100644 index 0000000..e60d315 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page.dart @@ -0,0 +1,80 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/icon.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage extends StatefulWidget { + const StaticTabPage({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState(); + } +} + +class StaticTabPageState extends State { + // List> _children = new List(); + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 定义tab文字 + List _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + // 子页面 + List _children = [ + new IconfontIcon(code: 0xe60e), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + ), + body: new DefaultTabController( + length: 3, + child: new Column(children: [ + new Material( + color: Theme.of(context).primaryColor, + //elevation: 4.0, + child: new SizedBox( + height: 48.0, + width: double.infinity, + child: new TabBar( + // isScrollable: true, // 是否滚动 + indicatorWeight: 4, // 标签高度 + indicatorSize: + TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + tabs: _tabs, + ), + ), + ), + new Expanded(child: new TabBarView(children: _children)) + ])), + ); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/demo/tabPage/static_tab_page2.dart b/lib/ui/pages/demo/tabPage/static_tab_page2.dart new file mode 100644 index 0000000..9931446 --- /dev/null +++ b/lib/ui/pages/demo/tabPage/static_tab_page2.dart @@ -0,0 +1,68 @@ +import 'package:base_app/res/index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class StaticTabPage2 extends StatefulWidget { + const StaticTabPage2({Key key, this.labelId, this.title, this.titleId}) + : super(key: key); + + final String labelId; + final String title; + final String titleId; + + @override + State createState() { + return new StaticTabPageState2(); + } +} + +class StaticTabPageState2 extends State + with SingleTickerProviderStateMixin { + TabController _controller; + List _tabs; + + @override + void initState() { + super.initState(); + _controller = TabController(initialIndex: 0, length: 3, vsync: this); + // 定义tab文字 + _tabs = [ + Tab(text: "选项卡1"), + Tab(text: "选项卡2"), + Tab(text: "选项卡3"), + ]; + } + + @override + Widget build(BuildContext context) { + // 子页面 + List _children = [ + new Text("tab1"), + new Text("tab2"), + new Text("tab3") + ]; + return new Scaffold( + appBar: new AppBar( + elevation: 0.0, //控件的zindex, 可以隐藏阴影 + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId)), + centerTitle: true, // 标题居中 + bottom: TabBar( + indicatorWeight: 4, // 标签高度 + indicatorSize: TabBarIndicatorSize.tab, // 标签长度,等宽用tab, 实际用label + indicatorColor: Colours.blue_light, // 选中时标签下方的颜色 + controller: _controller, + tabs: _tabs, + ), + ), + body: new TabBarView(controller: _controller, children: _children)); + } + + @override + void dispose() { + // for (int i = 0, length = _children.length; i < length; i++) { + // _children[i].bloc.dispose(); + // } + super.dispose(); + } +} diff --git a/lib/ui/pages/main_left_page.dart b/lib/ui/pages/main_left_page.dart new file mode 100644 index 0000000..8e906d6 --- /dev/null +++ b/lib/ui/pages/main_left_page.dart @@ -0,0 +1,189 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; + +import 'common/about_page.dart'; +import 'common/setting_page.dart'; + +/// 侧边抽屉 +class MainLeftPage extends StatefulWidget { + @override + State createState() { + return new _MainLeftPageState(); + } +} + +class PageInfo { + PageInfo(this.titleId, this.iconData, this.page, [this.withScaffold = true]); + + String titleId; + IconData iconData; + Widget page; + bool withScaffold; +} + +class _MainLeftPageState extends State { + List _pageInfo = new List(); + PageInfo loginOut = + PageInfo(Ids.titleSignOut, Icons.power_settings_new, null); + String _userName = '--'; + + @override + void initState() { + super.initState(); + _pageInfo.add(PageInfo(Ids.titleSetting, Icons.settings, SettingPage())); + _pageInfo.add(PageInfo(Ids.titleAbout, Icons.info, AboutPage())); + } + + /// 注销 + void _showLoginOutDialog(BuildContext context) { + showDialog( + context: context, + builder: (ctx) { + return AlertDialog( + content: Text( + IntlUtil.getString(context, Ids.hint_quit), + ), + actions: [ + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.cancel), + style: TextStyles.listExtra, + ), + onPressed: () { + Navigator.pop(ctx); + }, + ), + FlatButton( + child: Text( + IntlUtil.getString(ctx, Ids.confirm), + style: TextStyles.listExtra, + ), + onPressed: () { + UserRepository userRepository = new UserRepository(); + userRepository.logout().then((result) { + if (result) { + SpUtil.remove(BaseConstant.keyAppToken); + // 打开登录页,并将其他路由删除 + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + } + }).catchError((onError) { + SpUtil.remove(BaseConstant.keyAppToken); + Navigator.of(context).pushNamedAndRemoveUntil( + BaseConstant.routeLogin, (route) => false); + }); + }, + ), + ], + ); + }); + } + + @override + Widget build(BuildContext context) { + // 判断是否已登录,已登录显示用户名和退出 + UserModel userModel = + SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + if (userModel != null) { + if (!_pageInfo.contains(loginOut)) { + _pageInfo.add(loginOut); + UserModel userModel = SpUtil.getObj( + BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + setState(() { + _userName = userModel?.name ?? ""; + }); + LogUtil.e("_userName : $_userName"); + } + } else { + setState(() { + _userName = "未登录"; + }); + if (_pageInfo.contains(loginOut)) { + _pageInfo.remove(loginOut); + } + } + + return new Scaffold( + body: new Column( + children: [ + new Container( + height: 166.0, + color: Theme.of(context).primaryColor, + padding: EdgeInsets.only( + top: ScreenUtil.getInstance().statusBarHeight, left: 10.0), + child: new Stack( + children: [ + new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Container( + width: 64.0, + height: 64.0, + margin: EdgeInsets.only(top: 10.0, bottom: 10.0), + decoration: BoxDecoration( + shape: BoxShape.circle, + image: DecorationImage( + image: AssetImage( + Utils.getImgPath('default_avatar', format: 'jpg'), + ), + ), + ), + ), + new Text( + _userName, + style: new TextStyle( + color: Colors.white, + fontSize: 16.0, + fontWeight: FontWeight.bold), + ), + Gaps.vGap5, + new Text( + "个人简介", + style: new TextStyle(color: Colors.white, fontSize: 12.0), + ), + ], + ), + new Align( + alignment: Alignment.topRight, + child: new IconButton( + iconSize: 18.0, + icon: new Icon(Icons.edit, color: Colors.white), + onPressed: () {}), + ) + ], + ), + ), + new Expanded( + child: new ListView.builder( + padding: const EdgeInsets.all(0.0), + itemCount: _pageInfo.length, + itemBuilder: (BuildContext context, int index) { + PageInfo pageInfo = _pageInfo[index]; + return new ListTile( + leading: new Icon(pageInfo.iconData), + title: Text(IntlUtil.getString(context, pageInfo.titleId)), + onTap: () { + if (pageInfo.titleId == Ids.titleSignOut) { + _showLoginOutDialog(context); + } else { + NavigatorUtil.pushPage(context, pageInfo.page, + pageName: pageInfo.titleId, + needLogin: Utils.isNeedLogin(pageInfo.titleId)); + } + }, + ); + }), + flex: 1, + ) + ], + ), + ); + } +} diff --git a/lib/ui/pages/main_page.dart b/lib/ui/pages/main_page.dart new file mode 100644 index 0000000..69d8f53 --- /dev/null +++ b/lib/ui/pages/main_page.dart @@ -0,0 +1,120 @@ +import 'package:base_app/blocs/list_bloc.dart'; +import 'package:base_app/blocs/bloc_index.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/pages/demo/list_page.dart'; +import 'package:base_app/ui/pages/demo/map_page.dart'; +import 'package:base_app/ui/pages/demo/demo_tab_page.dart'; +import 'package:base_app/ui/pages/main_left_page.dart'; +import 'package:base_app/ui/widgets/common/button/large_button_widget.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +import 'demo/simple_page.dart'; + +// 页面 +class _Page { + final String labelId; + _Page(this.labelId); +} + +final List<_Page> _allPages = <_Page>[ + _Page(Ids.titleHome), + _Page(Ids.titleRepos), + _Page(Ids.titleEvents), + _Page(Ids.titleList), +]; + +/// 主菜单页 +class MainPage extends StatefulWidget { + @override + State createState() { + return new MainPageState(); + } +} + +class MainPageState extends State { + DateTime _lastPressedAt; //上次点击时间 + int _currentIndex = 0; + List _pages; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + // 全局 + return Scaffold( + appBar: AppBar( + title: Text( + IntlUtil.getString(context, _allPages[_currentIndex].labelId)), + centerTitle: true, + ), + // 抽屉 + drawer: Drawer(child: MainLeftPage()), + // 底部导航栏 + bottomNavigationBar: BottomNavigationBar( + currentIndex: _currentIndex, //当前tab + selectedItemColor: Theme.of(context).primaryColor, // 选中后的颜色 + type: BottomNavigationBarType.fixed, // 类别fixed和shift + unselectedItemColor: Colours.gray_66, //未选中颜色 + onTap: (int index) { + setState(() { + _currentIndex = index; + }); + }, + items: [ + BottomNavigationBarItem( + title: new Text("simple"), icon: new Icon(Icons.home)), + BottomNavigationBarItem( + title: new Text("tab"), icon: new Icon(Icons.tab)), + BottomNavigationBarItem( + title: new Text("map"), icon: new Icon(Icons.map)), + BottomNavigationBarItem( + title: new Text("list"), icon: new Icon(Icons.list)), + ]), + // 监控返回按钮 + body: new WillPopScope( + child: buildTabView(context, _currentIndex), + onWillPop: () async { + if (_lastPressedAt == null || + DateTime.now().difference(_lastPressedAt) > + Duration(seconds: 2)) { + showToast("再按一次退出程序"); + //两次点击间隔超过1秒则重新计时 + _lastPressedAt = DateTime.now(); + return false; + } + return true; + })); + } + + Widget buildTabView(BuildContext context, index) { + _Page page = _allPages[index]; + String labelId = page.labelId; + switch (labelId) { + case Ids.titleHome: + return SimplePage(labelId: labelId); + break; + case Ids.titleRepos: + return DemoTabPage(labelId: labelId); + break; + case Ids.titleEvents: + return MapPage(labelId: labelId); + break; + case Ids.titleList: + // new Bloc + return new BlocProvider( + child: ListPage(labelId: labelId), bloc: new ListBloc()); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/pages/splash_page.dart b/lib/ui/pages/splash_page.dart new file mode 100644 index 0000000..cfa792f --- /dev/null +++ b/lib/ui/pages/splash_page.dart @@ -0,0 +1,289 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/res/colors.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/http_utils.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flukit/flukit.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:rxdart/rxdart.dart'; + +/// 闪屏页(闪屏、导航、广告) +class SplashPage extends StatefulWidget { + @override + State createState() { + return new SplashPageState(); + } +} + +class SplashPageState extends State { + TimerUtil _timerUtil; + + // 本地导航列表 + List _guideList = [ + Utils.getImgPath('guide1'), + Utils.getImgPath('guide2'), + Utils.getImgPath('guide3') + ]; + + List _bannerList = new List(); + + int _status = 0; + int _count = 3; + + SplashModel _splashModel; + + @override + void initState() { + super.initState(); + _init(); + } + + void _init() { + // 加载导航数据 + _loadSplashData(); + Observable.just(1).delay(new Duration(milliseconds: 500)).listen((_) { + // 判断是否需要闪屏,需要则加载,不需要则直接加载banner + if (SpUtil.getBool(Constant.key_guide, defValue: true) && + ObjectUtil.isNotEmpty(_guideList)) { + SpUtil.putBool(Constant.key_guide, false); + _initBanner(); + } else { + _initSplash(); + } + }); + } + + /// 加载闪屏数据,先看本地有没有闪屏数据 + void _loadSplashData() { + //1. 先读取本地 + _splashModel = SpUtil.getObj( + Constant.key_splash_model, (v) => SplashModel.fromJson(v)); + if (_splashModel != null) { + setState(() {}); + } else { + // 2. 本地没有缓存的话,访问远程 + HttpUtils httpUtil = new HttpUtils(); + httpUtil.getSplash().then((model) { + if (!ObjectUtil.isEmpty(model.imgUrl)) { + if (_splashModel == null || (_splashModel.imgUrl != model.imgUrl)) { + SpUtil.putObject(Constant.key_splash_model, model); + setState(() { + _splashModel = model; + }); + } + } else { + SpUtil.putObject(Constant.key_splash_model, null); + } + }); + } + } + + void _initBanner() { + _initBannerData(); + setState(() { + _status = 2; + }); + } + + void _initBannerData() { + for (int i = 0, length = _guideList.length; i < length; i++) { + if (i == length - 1) { + // 最后一页,显示立即体验,点击之后去主页 + _bannerList.add(new Stack( + children: [ + new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + ), + new Align( + alignment: Alignment.bottomCenter, + child: new Container( + margin: EdgeInsets.only(bottom: 160.0), + child: new InkWell( + onTap: () { + _goMain(); + }, + child: new CircleAvatar( + radius: 48.0, + backgroundColor: Colors.indigoAccent, + child: new Padding( + padding: EdgeInsets.all(2.0), + child: new Text( + '立即体验', + textAlign: TextAlign.center, + style: TextStyle(color: Colors.white, fontSize: 16.0), + ), + ), + ), + ), + ), + ), + ], + )); + } else { + // 其他页返回图片 + _bannerList.add(new Image.asset( + _guideList[i], + fit: BoxFit.fill, + width: double.infinity, + height: double.infinity, + )); + } + } + } + + void _initSplash() { + if (_splashModel == null) { + _goMain(); + } else { + new Timer(new Duration(milliseconds: 500), () { + _doCountDown(); + }); + } + } + + // 倒计时,3s后进入主页 + void _doCountDown() { + setState(() { + _status = 1; + }); + _timerUtil = new TimerUtil(mTotalTime: 3 * 1000); + _timerUtil.setOnTimerTickCallback((int tick) { + double _tick = tick / 1000; + setState(() { + _count = _tick.toInt(); + }); + if (_tick == 0) { + _goMain(); + } + }); + _timerUtil.startCountDown(); + } + + // 去主页 + void _goMain() async { + // 判断是否已登录,已登录跳转到主页,否则去登录页 + bool isLogin = await LoginUtils.isLogin(); + if (isLogin) { + RouteUtil.goMain(context); + } else { + RouteUtil.goLogin(context); + } + } + + // 构建闪屏页 + Widget _buildSplashBg() { + return new Image.asset( + Utils.getImgPath('splash_bg'), + width: double.infinity, + fit: BoxFit.fill, + height: double.infinity, + ); + } + + // 构建广告页 + Widget _buildAdWidget() { + if (_splashModel == null) { + return new Container( + height: 0.0, + ); + } + return new Offstage( + offstage: !(_status == 1), + child: new InkWell( + onTap: () { + if (ObjectUtil.isEmpty(_splashModel.url)) return; + _goMain(); + NavigatorUtil.pushWeb(context, + title: _splashModel.title, url: _splashModel.url); + }, + child: new Container( + alignment: Alignment.center, + child: new CachedNetworkImage( + width: double.infinity, + height: double.infinity, + fit: BoxFit.fill, + imageUrl: _splashModel.imgUrl, + placeholder: (context, url) => _buildSplashBg(), + errorWidget: (context, url, error) => _buildSplashBg(), + ), + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + child: new Stack( + children: [ + // offstage组件,offstage属性为false时显示 + new Offstage( + // _status为0,显示闪屏 + offstage: !(_status == 0), + child: _buildSplashBg(), + ), + new Offstage( + // _status为2,显示导航 + offstage: !(_status == 2), + child: ObjectUtil.isEmpty(_bannerList) + ? new Container() + : new Swiper( + autoStart: false, + circular: false, + indicator: CircleSwiperIndicator( + radius: 4.0, + padding: EdgeInsets.only(bottom: 30.0), + itemColor: Colors.black26, + ), + children: _bannerList), + ), + // 显示广告 + _buildAdWidget(), + new Offstage( + // _status为1显示跳过 + offstage: !(_status == 1), + child: new Container( + alignment: Alignment.bottomRight, + margin: EdgeInsets.all(20.0), + child: InkWell( + onTap: () { + _goMain(); + }, + child: new Container( + padding: EdgeInsets.all(12.0), + child: new Text( + // 跳过 + IntlUtil.getString(context, Ids.jump_count, + params: ['$_count']), + style: new TextStyle(fontSize: 14.0, color: Colors.white), + ), + decoration: new BoxDecoration( + color: Color(0x66000000), + borderRadius: BorderRadius.all(Radius.circular(4.0)), + border: new Border.all( + width: 0.33, color: Colours.divider))), + ), + ), + ) + ], + ), + ); + } + + @override + void dispose() { + super.dispose(); + if (_timerUtil != null) _timerUtil.cancel(); //记得在dispose里面把timer cancel。 + } +} diff --git a/lib/ui/pages/user/user_login_page.dart b/lib/ui/pages/user/user_login_page.dart new file mode 100644 index 0000000..f615d15 --- /dev/null +++ b/lib/ui/pages/user/user_login_page.dart @@ -0,0 +1,258 @@ +import 'dart:async'; + +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/net/dio_util.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/styles.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:base_app/ui/widgets/common/dialog/loading_dialog_widget.dart'; +import 'package:base_app/ui/widgets/login_page/login_item_widget.dart'; +import 'package:base_app/utils/route_util.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:dio/dio.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:oktoast/oktoast.dart'; + +// 登录页Widget +class UserLoginPage extends StatefulWidget { + @override + State createState() { + return new LoginPageState(); + } +} + +// 登录页State +class LoginPageState extends State { + // 用户仓库(调用后台) + UserRepository userRepository = new UserRepository(); + @override + initState() { + super.initState(); + // 显示loding窗口 + Future.delayed(Duration.zero, () { + // 1. 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "连接服务器中...", + ); + }); + // 2. 连接后台服务器 + userRepository.baseConfig().then((result) { + Navigator.pop(context); // 关闭弹窗 + }).catchError((onError) { + Navigator.pop(context); // 关闭弹窗并提示错误信息 + showToast("连接服务器失败,请稍后退出重进~"); + }); + }); + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + resizeToAvoidBottomInset: false, + body: new Stack( + children: [ + new Image.asset( + Utils.getImgPath("ic_login_bg"), + width: double.infinity, + height: double.infinity, + fit: BoxFit.cover, + ), // 背景图片 + new LoginBody() + ], + ), + ); + } +} + +// 登录BodyWidgegt +class LoginBody extends StatelessWidget { + UserRepository userRepository = new UserRepository(); // 用户信息仓库 + + TextEditingController _controllerPort = new TextEditingController(); // 地址 + TextEditingController _controllerName = new TextEditingController(); // 账户 + TextEditingController _controllerPwd = new TextEditingController(); // 密码 + + FocusNode passwordFocusNode = FocusNode(); + + @override + Widget build(BuildContext context) { + _controllerPort.text = SpUtil.getString(Constant.key_url); + // UserModel userModel = + // SpUtil.getObj(BaseConstant.keyUserModel, (v) => UserModel.fromJson(v)); + // _controllerName.text = userModel?.username ?? ""; + MediaQueryData mq = MediaQuery.of(context); + + /// 登录 + void _userLogin() { + String username = _controllerName.text.trim(); + String password = _controllerPwd.text.trim(); + if (username.isEmpty) { + Utils.showSnackBar(context, "请输入用户名~"); + return; + } + if (password.isEmpty) { + Utils.showSnackBar(context, "请输入密码~"); + return; + } + // 显示loading窗 + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return new LoadingDialog( + text: "登录中…", + ); + }); + + // 调后台验证登录 + LoginReq req = new LoginReq(username, password); + userRepository.login(req).then((UserModel model) { + LogUtil.e("LoginResp: ${model.toString()}"); + Navigator.pop(context); + showToast("登录成功~"); + Timer timer = new Timer(new Duration(milliseconds: 500), () { + RouteUtil.goMain(context); + }); + // }); + }).catchError((error) { + Navigator.pop(context); + if (error is String) { + // Utils.showSnackBar(context, error.toString()); + showToast(error.toString()); + } else { + showToast("未知异常,请退出后重试"); + LogUtil.e("LoginResp error: ${error.toString()}"); + } + }); + } + + void openUrlSetting(context) { + // 打开服务器配置弹窗 + showCupertinoDialog( + context: context, + builder: (context) { + return Container( + child: CupertinoAlertDialog( + title: Text('请输入后台服务器地址'), + content: new Container( + padding: EdgeInsets.only(top: 10.0), + child: new CupertinoTextField( + controller: _controllerPort, + minLines: 1, + maxLines: 2, + placeholder: "如:http://127.0.0.01:8080/", + )), + actions: [ + CupertinoDialogAction( + onPressed: () { + // 放弃返回主页 + Navigator.pop(context); + }, + child: Text('取消'), + ), + CupertinoDialogAction( + onPressed: () { + String url = _controllerPort.text; + // 如果没有末尾斜杠加上斜杠 + if (url[url.length - 1] != '/') { + url = url + '/'; + } + SpUtil.putString(Constant.key_url, url); + Options options = DioUtil.getDefOptions(); + options.baseUrl = url; + HttpConfig config = new HttpConfig(options: options); + DioUtil().setConfig(config); + Navigator.pop(context); + showToast("保存成功"); + connectServer(); // 重新连接服务器 + }, + child: Text('保存'), + ) + ])); + }); + } + + return new Column( + children: [ + new Container( + height: mq.size.height / 3, + alignment: Alignment.center, + child: Text( + AppConfig.appName, + style: TextStyle(color: Colors.white, fontSize: 22), + ), + ), // 标题 + new Expanded( + child: new Container( + margin: EdgeInsets.only(left: 20, top: 15, right: 20), + child: new Column( + children: [ + // 用户名输入框 + LoginItem( + textInputAction: TextInputAction.next, + onEditingComplete: () => + FocusScope.of(context).requestFocus(passwordFocusNode), + // autoFocus: true, + keyboardType: TextInputType.emailAddress, + controller: _controllerName, + prefixIcon: Icons.person, + hintText: IntlUtil.getString(context, Ids.user_name), + ), + Gaps.vGap15, + // 密码输入框 + LoginItem( + textInputAction: TextInputAction.done, + focusNode: passwordFocusNode, + controller: _controllerPwd, + prefixIcon: Icons.lock, + hasSuffixIcon: true, + hintText: IntlUtil.getString(context, Ids.user_pwd), + ), + // 服务器配置 + new Container( + padding: EdgeInsets.only(top: Dimens.gap_dp15), + alignment: Alignment.centerRight, + child: new InkWell( + child: new Text( + IntlUtil.getString(context, Ids.server_url_set), + style: new TextStyle( + color: Colours.gray_99, fontSize: Dimens.font_sp14), + ), + onTap: () { + openUrlSetting(context); + }, + ), + ), + new RoundButton( + text: "登录", + margin: EdgeInsets.only(top: 20), + onPressed: () { + _userLogin(); + }, + ), + Gaps.vGap15, + ], + ), + )), + ], + ); + } + + // 连接服务器 + connectServer() { + userRepository.baseConfig().then((result) { + showToast("连接服务器成功"); + }).catchError((onError) { + showToast("连接服务器失败,请确认服务器地址是否填写正确"); + }); + } +} diff --git a/lib/ui/widgets/common/button/large_button_widget.dart b/lib/ui/widgets/common/button/large_button_widget.dart new file mode 100644 index 0000000..e02d9b3 --- /dev/null +++ b/lib/ui/widgets/common/button/large_button_widget.dart @@ -0,0 +1,89 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:flutter/material.dart'; + +/// 功能模块按钮 +class LargeButton extends StatelessWidget { + const LargeButton({ + Key key, + this.width, + this.height, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.iconPath, + this.text, + this.style, + this.onTap, + }) : super(key: key); + + final double width; // 宽度 + final double height; // 高度 + + /// Empty space to surround the [decoration] and [child]. + final EdgeInsetsGeometry margin; // 外边距 + + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 点击后的颜色 + final Color splashColor; // 闪烁颜色 + + final Widget child; // 子元素 + + final String text; // 显示文字 + final String iconPath; // 图标路径 + final TextStyle style; // 文字样式 + + final VoidCallback onTap; // 点击后的回调 + + @override + Widget build(BuildContext context) { + return new Container( + height: height ?? 120, + margin: + const EdgeInsets.only(left: 20.0, right: 20, top: 10, bottom: 10), + decoration: new BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colours.divider, + offset: Offset(1.0, 2.0), + blurRadius: 5.0, + spreadRadius: 2.0), + BoxShadow(color: Colors.white, offset: Offset(1.0, 1.0)), + ], + borderRadius: new BorderRadius.all(new Radius.circular(8.0)), + ), + child: RaisedButton( + color: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(6.0)), + onPressed: onTap, + child: new Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + // logo + iconPath == null || iconPath == "" + ? new Container() + : new Image.asset( + Utils.getImgPath(iconPath), + width: 25.0, + height: 25.0, + fit: BoxFit.fitHeight, + ), + new Container( + margin: const EdgeInsets.only(left: 8.0), + alignment: Alignment.center, + child: new Center( + child: new Text( + this.text, + style: new TextStyle( + fontWeight: FontWeight.bold, fontSize: 20.0), + ), + )) + ], + ))); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/circle_painter.dart b/lib/ui/widgets/common/button/likebtn/circle_painter.dart new file mode 100644 index 0000000..b9d709a --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/circle_painter.dart @@ -0,0 +1,45 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; + +class CirclePainter extends CustomPainter { + Paint circlePaint = new Paint(); + Paint maskPaint = new Paint(); + + final double outerCircleRadiusProgress; + final double innerCircleRadiusProgress; + final Color startColor; + final Color endColor; + + CirclePainter({ + @required this.outerCircleRadiusProgress, + @required this.innerCircleRadiusProgress, + this.startColor = const Color(0xFFFF5722), + this.endColor = const Color(0xFFFFC107), + }) { + circlePaint..style = PaintingStyle.fill; + maskPaint..blendMode = BlendMode.clear; + } + + @override + void paint(Canvas canvas, Size size) { + double center = size.width * 0.5; + _updateCircleColor(); + canvas.saveLayer(Offset.zero & size, Paint()); + canvas.drawCircle(Offset(center, center), + outerCircleRadiusProgress * center, circlePaint); + canvas.drawCircle(Offset(center, center), + innerCircleRadiusProgress * center + 1, maskPaint); + canvas.restore(); + } + + void _updateCircleColor() { + double colorProgress = clamp(outerCircleRadiusProgress, 0.5, 1.0); + colorProgress = mapValueFromRangeToRange(colorProgress, 0.5, 1.0, 0.0, 1.0); + circlePaint..color = Color.lerp(startColor, endColor, colorProgress); + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/dot_painter.dart b/lib/ui/widgets/common/button/likebtn/dot_painter.dart new file mode 100644 index 0000000..ee6cd71 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/dot_painter.dart @@ -0,0 +1,158 @@ +import 'package:base_app/ui/widgets/common/button/likebtn/like_button_util.dart'; +import 'package:flutter/material.dart'; +import 'dart:math' as math; + +class DotPainter extends CustomPainter { + final int dotCount; + double outerDotsPositionAngle = 51.42; + + final Color color1; + final Color color2; + final Color color3; + final Color color4; + + double centerX = 0.0; + double centerY = 0.0; + + final List circlePaints = List(4); + + double maxOuterDotsRadius = 0.0; + double maxInnerDotsRadius = 0.0; + double maxDotSize; + + final currentProgress; + + double currentRadius1 = 0.0; + double currentDotSize1 = 0.0; + double currentDotSize2 = 0.0; + double currentRadius2 = 0.0; + + bool isFirst = true; + + DotPainter({ + @required this.currentProgress, + this.dotCount = 7, + this.color1 = const Color(0xFFFFC107), + this.color2 = const Color(0xFFFF9800), + this.color3 = const Color(0xFFFF5722), + this.color4 = const Color(0xFFF44336), + }) { + outerDotsPositionAngle = 360.0 / dotCount; + for (int i = 0; i < circlePaints.length; i++) { + circlePaints[i] = new Paint()..style = PaintingStyle.fill; + } + } + + @override + void paint(Canvas canvas, Size size) { + if (isFirst) { + centerX = size.width * 0.5; + centerY = size.height * 0.5; + maxDotSize = size.width * 0.05; + maxOuterDotsRadius = size.width * 0.5 - maxDotSize * 2; + maxInnerDotsRadius = 0.8 * maxOuterDotsRadius; + isFirst = false; + } + _updateOuterDotsPosition(); + _updateInnerDotsPosition(); + _updateDotsPaints(); + _drawOuterDotsFrame(canvas); + _drawInnerDotsFrame(canvas); + } + + void _drawOuterDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius1 * math.cos(i * degToRad(outerDotsPositionAngle)); + double cY = centerY + + currentRadius1 * math.sin(i * degToRad(outerDotsPositionAngle)); + canvas.drawCircle(Offset(cX, cY), currentDotSize1, + circlePaints[i % circlePaints.length]); + } + } + + void _drawInnerDotsFrame(Canvas canvas) { + for (int i = 0; i < dotCount; i++) { + double cX = centerX + + currentRadius2 * + math.cos((i * degToRad(outerDotsPositionAngle - 10))); + double cY = centerY + + currentRadius2 * + math.sin((i * degToRad(outerDotsPositionAngle - 10))); + canvas.drawCircle(Offset(cX, cY), currentDotSize2, + circlePaints[(i + 1) % circlePaints.length]); + } + } + + void _updateOuterDotsPosition() { + if (currentProgress < 0.3) { + currentRadius1 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxOuterDotsRadius * 0.8); + } else { + currentRadius1 = mapValueFromRangeToRange(currentProgress, 0.3, 1.0, + 0.8 * maxOuterDotsRadius, maxOuterDotsRadius); + } + if (currentProgress == 0) { + currentDotSize1 = 0; + } else if (currentProgress < 0.7) { + currentDotSize1 = maxDotSize; + } else { + currentDotSize1 = + mapValueFromRangeToRange(currentProgress, 0.7, 1.0, maxDotSize, 0.0); + } + } + + void _updateInnerDotsPosition() { + if (currentProgress < 0.3) { + currentRadius2 = mapValueFromRangeToRange( + currentProgress, 0.0, 0.3, 0.0, maxInnerDotsRadius); + } else { + currentRadius2 = maxInnerDotsRadius; + } + if (currentProgress == 0) { + currentDotSize2 = 0; + } else if (currentProgress < 0.2) { + currentDotSize2 = maxDotSize; + } else if (currentProgress < 0.5) { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.2, 0.5, maxDotSize, 0.3 * maxDotSize); + } else { + currentDotSize2 = mapValueFromRangeToRange( + currentProgress, 0.5, 1.0, maxDotSize * 0.3, 0.0); + } + } + + void _updateDotsPaints() { + double progress = clamp(currentProgress, 0.6, 1.0); + int alpha = + mapValueFromRangeToRange(progress, 0.6, 1.0, 255.0, 0.0).toInt(); + if (currentProgress < 0.5) { + double progress = + mapValueFromRangeToRange(currentProgress, 0.0, 0.5, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + } else { + double progress = + mapValueFromRangeToRange(currentProgress, 0.5, 1.0, 0.0, 1.0); + circlePaints[0] + ..color = Color.lerp(color2, color3, progress).withAlpha(alpha); + circlePaints[1] + ..color = Color.lerp(color3, color4, progress).withAlpha(alpha); + circlePaints[2] + ..color = Color.lerp(color4, color1, progress).withAlpha(alpha); + circlePaints[3] + ..color = Color.lerp(color1, color2, progress).withAlpha(alpha); + } + } + + @override + bool shouldRepaint(CustomPainter oldDelegate) { + return true; + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button.dart b/lib/ui/widgets/common/button/likebtn/like_button.dart new file mode 100644 index 0000000..39a4904 --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button.dart @@ -0,0 +1,170 @@ +import 'package:flutter/material.dart'; + +import 'circle_painter.dart'; +import 'dot_painter.dart'; +import 'model.dart'; + +typedef LikeCallback = void Function(bool isLike); + +class LikeButton extends StatefulWidget { + final double width; + final LikeIcon icon; + final Duration duration; + final DotColor dotColor; + final Color circleStartColor; + final Color circleEndColor; + final LikeCallback onIconClicked; + + const LikeButton({ + Key key, + @required this.width, + this.icon = const LikeIcon( + Icons.favorite, + iconColor: Colors.pinkAccent, + ), + this.duration = const Duration(milliseconds: 5000), + this.dotColor = const DotColor( + dotPrimaryColor: const Color(0xFFFFC107), + dotSecondaryColor: const Color(0xFFFF9800), + dotThirdColor: const Color(0xFFFF5722), + dotLastColor: const Color(0xFFF44336), + ), + this.circleStartColor = const Color(0xFFFF5722), + this.circleEndColor = const Color(0xFFFFC107), + this.onIconClicked, + }) : super(key: key); + + @override + State createState() => _LikeButtonState(); +} + +class _LikeButtonState extends State with TickerProviderStateMixin { + AnimationController _controller; + Animation outerCircle; + Animation innerCircle; + Animation scale; + Animation dots; + + bool isLiked = false; + + @override + void initState() { + super.initState(); + _controller = + new AnimationController(duration: widget.duration, vsync: this) + ..addListener(() { + setState(() {}); + }); + _initAllAmimations(); + } + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + CustomPaint( + size: Size(widget.width, widget.width), + painter: DotPainter( + currentProgress: dots.value, + color1: widget.dotColor.dotPrimaryColor, + color2: widget.dotColor.dotSecondaryColor, + color3: widget.dotColor.dotThirdColorReal, + color4: widget.dotColor.dotLastColorReal, + ), + ), + CustomPaint( + size: Size(widget.width * 0.35, widget.width * 0.35), + painter: CirclePainter( + innerCircleRadiusProgress: innerCircle.value, + outerCircleRadiusProgress: outerCircle.value, + startColor: widget.circleStartColor, + endColor: widget.circleEndColor), + ), + Container( + width: widget.width, + height: widget.width, + alignment: Alignment.center, + child: Transform.scale( + scale: isLiked ? scale.value : 1.0, + child: GestureDetector( + child: Icon( + widget.icon.icon, + color: isLiked ? widget.icon.color : Colors.grey, + size: widget.width * 0.4, + ), + onTap: _onTap, + ), + ), + ), + ], + ); + } + + void _onTap() { + if (_controller.isAnimating) return; + isLiked = !isLiked; + if (isLiked) { + _controller.reset(); + _controller.forward(); + } else { + setState(() {}); + } + if (widget.onIconClicked != null) widget.onIconClicked(isLiked); + } + + void _initAllAmimations() { + outerCircle = new Tween( + begin: 0.1, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.0, + 0.3, + curve: Curves.ease, + ), + ), + ); + innerCircle = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.2, + 0.5, + curve: Curves.ease, + ), + ), + ); + scale = new Tween( + begin: 0.2, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.35, + 0.7, + curve: OvershootCurve(), + ), + ), + ); + dots = new Tween( + begin: 0.0, + end: 1.0, + ).animate( + new CurvedAnimation( + parent: _controller, + curve: new Interval( + 0.1, + 1.0, + curve: Curves.decelerate, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/button/likebtn/like_button_util.dart b/lib/ui/widgets/common/button/likebtn/like_button_util.dart new file mode 100644 index 0000000..00d940f --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/like_button_util.dart @@ -0,0 +1,13 @@ +import 'dart:math' as math; + +num degToRad(num deg) => deg * (math.pi / 180.0); + +num radToDeg(num rad) => rad * (180.0 / math.pi); + +double mapValueFromRangeToRange(double value, double fromLow, double fromHigh, double toLow, double toHigh) { + return toLow + ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)); +} + +double clamp(double value, double low, double high) { + return math.min(math.max(value, low), high); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/button/likebtn/model.dart b/lib/ui/widgets/common/button/likebtn/model.dart new file mode 100644 index 0000000..73e36fd --- /dev/null +++ b/lib/ui/widgets/common/button/likebtn/model.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +class DotColor { + final Color dotPrimaryColor; + final Color dotSecondaryColor; + final Color dotThirdColor; + final Color dotLastColor; + + const DotColor({ + @required this.dotPrimaryColor, + @required this.dotSecondaryColor, + this.dotThirdColor, + this.dotLastColor, + }); + + Color get dotThirdColorReal => + dotThirdColor == null ? dotPrimaryColor : dotThirdColor; + + Color get dotLastColorReal => + dotLastColor == null ? dotSecondaryColor : dotLastColor; +} + +class LikeIcon extends Icon { + final Color iconColor; + + const LikeIcon( + IconData icon, { + this.iconColor, + }) : super(icon); + + @override + Color get color => this.iconColor; +} + +class OvershootCurve extends Curve { + const OvershootCurve([this.period = 2.5]); + + final double period; + + @override + double transform(double t) { + assert(t >= 0.0 && t <= 1.0); + t -= 1.0; + return t * t * ((period + 1) * t + period) + 1.0; + } + + @override + String toString() { + return '$runtimeType($period)'; + } +} diff --git a/lib/ui/widgets/common/button/round_button_widget.dart b/lib/ui/widgets/common/button/round_button_widget.dart new file mode 100644 index 0000000..342bde7 --- /dev/null +++ b/lib/ui/widgets/common/button/round_button_widget.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; + +// 圆形按钮Widget +class RoundButton extends StatelessWidget { + const RoundButton({ + Key key, + this.width, + this.height = 50, + this.margin, + this.radius, + this.bgColor, + this.highlightColor, + this.splashColor, + this.child, + this.text, + this.style, + this.onPressed, + }) : super(key: key); + + final double width; // 宽 + final double height; // 高 + final EdgeInsetsGeometry margin; // 边距 + final double radius; // 圆角 + final Color bgColor; // 背景颜色 + final Color highlightColor; // 高亮颜色?未用到 + final Color splashColor; //?未用到 + + final Widget child; // 子元素 + + final String text; // 文字 + final TextStyle style; // 文字样式 + + final VoidCallback onPressed; // 点击后的回调 + + @override + Widget build(BuildContext context) { + Color _bgColor = bgColor ?? Theme.of(context).primaryColor; + BorderRadius _borderRadius = BorderRadius.circular(radius ?? (height / 2)); + return new Container( + width: width, + height: height, + margin: margin, + child: new Material( + borderRadius: _borderRadius, + color: _bgColor, + child: new InkWell( + borderRadius: _borderRadius, + onTap: () => onPressed(), + child: child ?? + new Center( + child: new Text( + text, + style: + style ?? new TextStyle(color: Colors.white, fontSize: 16), + ), + ), + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/com_item.dart b/lib/ui/widgets/common/com_item.dart new file mode 100644 index 0000000..7cf5106 --- /dev/null +++ b/lib/ui/widgets/common/com_item.dart @@ -0,0 +1,49 @@ +import 'package:base_app/models/common/component_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; + +class ComArrowItem extends StatelessWidget { + const ComArrowItem(this.model, {Key key}) : super(key: key); + final ComponentModel model; + + @override + Widget build(BuildContext context) { + return new Container( + child: new Material( + color: Colors.white, + child: new ListTile( + onTap: () { + if (model.page == null && model.url != null) { + // 跳转网页 + NavigatorUtil.pushWeb(context, + title: model.title, url: model.url); + } else { + // 跳转页面 + NavigatorUtil.pushPage(context, model.page, + pageName: model.title); + } + }, + // 标题 + title: new Text(model.title == null ? "" : model.title), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + // 其他文字 + model.extra == null ? "" : model.extra, + style: TextStyle(color: Colors.grey, fontSize: 14.0), + ), + new Icon( + // 向右箭头 + Icons.navigate_next, + color: Colors.grey, + ), + ], + ), + ), + ), + decoration: Decorations.bottom, + ); + } +} diff --git a/lib/ui/widgets/common/dialog/input_dialog_widget.dart b/lib/ui/widgets/common/dialog/input_dialog_widget.dart new file mode 100644 index 0000000..7a87de4 --- /dev/null +++ b/lib/ui/widgets/common/dialog/input_dialog_widget.dart @@ -0,0 +1,110 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 开始巡检的弹窗Widget +class inputDialogWidget extends StatefulWidget { + inputDialogWidget({ + Key key, + }) : super(key: key); + + @override + _inputDialogWidgetState createState() => _inputDialogWidgetState(); +} + +class _inputDialogWidgetState extends State { + TextEditingController _decController = TextEditingController(); + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () { + // 点击其他区域关闭 + FocusScope.of(context).requestFocus(FocusNode()); + }, + child: Container( + color: Colors.transparent, + width: double.infinity, + height: double.infinity, + child: Container( + padding: EdgeInsets.symmetric( + horizontal: 20.0, + vertical: (MediaQuery.of(context).size.height - 250) / 2), + child: Stack( + children: [ + Positioned( + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(5))), + child: Column( + children: [ + Gaps.vGap15, + // 标题 + Container( + alignment: Alignment.centerLeft, + padding: EdgeInsets.symmetric(horizontal: 20), + child: Text( + '巡检标签', + style: TextStyle( + fontSize: 14, + color: Color(0XFF333333), + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), + ), + Gaps.vGap10, + //输入框 + Container( + padding: EdgeInsets.symmetric(horizontal: 20), + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Color(0xFFEEEEEE), width: 0.5), + borderRadius: + BorderRadius.all(Radius.circular(4.0))), + child: TextField( + maxLines: 3, + maxLength: 100, + textInputAction: TextInputAction.done, + controller: _decController, + decoration: InputDecoration( + contentPadding: const EdgeInsets.all(10), + hintText: '如:XXXX区间巡检', + border: OutlineInputBorder( + borderSide: BorderSide.none), + hintStyle: + TextStyle(color: Colours.gray_cc), + )))), + // 按钮 + Container( + padding: EdgeInsets.all(20), + child: GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Container( + width: double.infinity, + height: 35.0, + alignment: Alignment.center, + decoration: BoxDecoration( + color: Color(0XFF2B95E9), + borderRadius: + BorderRadius.all(Radius.circular(4.0)), + ), + child: Text( + '开始巡检', + style: TextStyle( + color: Colors.white, fontSize: 14.0), + ), + ), + ), + ), + ], + ), + ), + ) + ], + )), + ), + ); + } +} diff --git a/lib/ui/widgets/common/dialog/loading_dialog_widget.dart b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart new file mode 100644 index 0000000..773ef0a --- /dev/null +++ b/lib/ui/widgets/common/dialog/loading_dialog_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; + +///自定义等待加载提示框 + +class LoadingDialog extends Dialog { + + final String text; // 显示文本 + + LoadingDialog({Key key, @required this.text}) : super(key: key); + + @override + Widget build(BuildContext context) { + return new Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 120.0, + height: 120.0, + child: new Container( + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + new CircularProgressIndicator(), + new Padding( + padding: const EdgeInsets.only( + top: 20.0, + ), + child: new Text(text), + ), + ], + ), + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart new file mode 100644 index 0000000..868f7ce --- /dev/null +++ b/lib/ui/widgets/common/dialog/select_item_dialog_widget.dart @@ -0,0 +1,69 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/ui/widgets/common/button/round_button_widget.dart'; +import 'package:flutter/material.dart'; + +// 两个选择弹窗(选择事件类型,选择查询类型用) +class SelectItemDialog extends Dialog { + final String title; // 标题 + final String btn1Text; // 第一个按钮文字 + final String btn2Text; // 第二个按钮文字 + final VoidCallback btn1OnPressed; // 第一个按钮点击回调 + final VoidCallback btn2OnPressed; // 第二个按钮点击回调 + + SelectItemDialog(this.title, + {Key key, + @required this.btn1Text, + @required this.btn2Text, + @required this.btn1OnPressed, + @required this.btn2OnPressed}) + : super(key: key); + + @override + Widget build(BuildContext context) { + return new GestureDetector( + onTap: () { + Navigator.pop(context); + }, + child: Material( + type: MaterialType.transparency, + child: new Center( + child: new SizedBox( + width: 220.0, + height: 220.0, + child: new Container( + padding: EdgeInsets.symmetric(horizontal: 30, vertical: 10), + decoration: ShapeDecoration( + color: Color(0xffffffff), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(8.0), + ), + ), + ), + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + title, + style: + TextStyle(fontSize: 18, fontWeight: FontWeight.bold), + ), + Gaps.vGap15, + new RoundButton( + radius: 8.0, + text: "$btn1Text", + onPressed: () => btn1OnPressed()), + Gaps.vGap10, + new RoundButton( + radius: 8.0, + text: "$btn2Text", + onPressed: () => btn2OnPressed()), + ], + ), + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart new file mode 100644 index 0000000..a8345a6 --- /dev/null +++ b/lib/ui/widgets/common/dialog/upgrade_dialog_widget.dart @@ -0,0 +1,260 @@ +import 'package:base_app/models/common/version_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/version_util.dart'; +import 'package:dio/dio.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; + +class UpgradeDialog extends StatefulWidget { + const UpgradeDialog({ + Key key, + this.versionModel, + this.appId, + }) : super(key: key); + final VersionModel versionModel; + final String appId; + + @override + State createState() { + return _UpgradeDialogState(); + } +} + +class _UpgradeDialogState extends State { + static const RoundedRectangleBorder _defaultDialogShape = + RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(4.0))); + + VersionModel versionModel; + + List listContent = List(); + + int progress = 0; + bool isDownload = false; + + OnDownloadProgress progressCallback; + + @override + void initState() { + super.initState(); + versionModel = widget.versionModel; + + progressCallback = (int count, int total) { + progress = ((count / total) * 100).toInt(); +// LogUtil.e( +// "ProgressCallback count: $count, total: $total, _progress: $progress"); + setState(() {}); + if (progress == 100) { + Navigator.pop(context); + } + }; + + VersionUtil().addListener(progressCallback); + +// versionModel.content = "1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~"; + if (ObjectUtil.isNotEmpty(versionModel.content)) + listContent = versionModel.content.split(' | '); + } + + @override + void dispose() { + super.dispose(); + VersionUtil().removeListener(progressCallback); + } + + @override + Widget build(BuildContext context) { + return MediaQuery.removeViewInsets( + removeLeft: true, + removeTop: true, + removeRight: true, + removeBottom: true, + context: context, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(minWidth: 310.0, maxWidth: 310), + child: Material( + color: Colors.white, + //elevation: _defaultElevation, + shape: _defaultDialogShape, + type: MaterialType.card, + child: isDownload + ? Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + width: 310, + height: 100, + color: Colors.blue, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Updating...', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Gaps.vGap20, + Offstage( + offstage: progress >= 0, + child: Text( + 'Network exception, download failed!', + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 14, color: Colors.redAccent), + ), + ), + Offstage( + offstage: progress < 0, + child: RichText( + textAlign: TextAlign.center, + text: TextSpan(children: [ + TextSpan( + style: TextStyle( + fontSize: 14, color: Colours.text_normal), + text: 'Progress '), + TextSpan( + style: TextStyle( + fontSize: 14, color: Colors.blueAccent), + text: "$progress%") + ]), + ), + ), + Gaps.vGap25, + Container( + padding: EdgeInsets.only(left: 24, right: 24), + height: 4, + child: LinearProgressIndicator( + backgroundColor: Colours.green_e5, + ), + ), + Gaps.vGap5, + Center( + child: FlatButton( + onPressed: () { + if (progress >= 0) { + Navigator.pop(context); + } else { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + } + }, + child: Text( + progress >= 0 ? 'Background Update' : 'Retry', + style: TextStyles.listExtra, + )), + ), + Gaps.vGap5, + ], + ) + : Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Stack( + children: [ + Container( + color: Colors.blue, + width: 310, + height: 100, + ), + Padding( + padding: EdgeInsets.all(24), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'New Version', + style: TextStyle( + fontSize: 24, color: Colors.white), + ), + Gaps.vGap5, + Text( + versionModel.version, + style: TextStyle( + fontSize: 22, color: Colors.white), + ), + ], + ), + ) + ], + ), + Padding( + padding: EdgeInsets.only(left: 24, top: 12), + child: Text( + 'Update Content', + style: TextStyles.listTitle, + ), + ), + Gaps.vGap15, + ListView.builder( + padding: EdgeInsets.only(left: 24, right: 24), + shrinkWrap: true, + physics: ClampingScrollPhysics(), + addRepaintBoundaries: false, + itemCount: listContent.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.only(top: 5, bottom: 5), + child: Text( + listContent[index], + style: TextStyles.listContent, + ), + ); + }), + Gaps.vGap10, + Row( + children: [ + Gaps.hGap10, + Expanded( + child: FlatButton( + onPressed: () { + Navigator.pop(context); + }, + child: Text( + 'Next', + style: TextStyles.listExtra, + ))), + Gaps.hGap5, + Expanded( + child: FlatButton( + onPressed: () { + VersionUtil().downloadApk( + versionModel.url, widget.appId); + setState(() { + isDownload = true; + }); + }, + child: Text( + 'Now', + style: TextStyles.listExtra2, + ))), + Gaps.hGap10, + ], + ), + ], + ), + ), + ), + )); + } +} diff --git a/lib/ui/widgets/common/icon.dart b/lib/ui/widgets/common/icon.dart new file mode 100644 index 0000000..0daf74e --- /dev/null +++ b/lib/ui/widgets/common/icon.dart @@ -0,0 +1,79 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class imageIcon extends StatelessWidget { + final String icon; // icon名称 + final double size; // 大小,默认20 + final EdgeInsetsGeometry margin; + + const imageIcon({Key key, this.icon, this.size = 20, this.margin}) + : super(key: key); // 外边距 + + @override + Widget build(BuildContext context) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Image( + image: AssetImage('assets/icons/$icon.png'), + width: size, + height: size)); + } +} + +// iconfont的icon的Widget +class IconfontIcon extends StatelessWidget { + final int code; // 16进制编码 + final IconData iconData; // iiconData格式 + final double size; // 大小,默认20 + final Color color; // 颜色,默认黑色 + final EdgeInsetsGeometry margin; // 外边距 + + const IconfontIcon( + {Key key, + this.code, + this.iconData, + this.size = 20, + this.margin, + this.color = Colors.black}) + : super(key: key); + + @override + Widget build(Object context) { + if (iconData != null) { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(iconData, size: size, color: color)); + } else { + return Container( + margin: margin ?? EdgeInsets.all(10), + child: Icon(IconData(code, fontFamily: 'IconFont'), + size: size, color: color)); + } + } +} + +// iconFont字典 +class IconfontIcons { + static const IconData icon_add = IconData(0xeb8f, fontFamily: 'iconfont'); + static const IconData icon_addmessage = + IconData(0xeb90, fontFamily: 'iconfont'); + static const IconData icon_addresslist = + IconData(0xeb91, fontFamily: 'iconfont'); + static const IconData icon_affiliations_li = + IconData(0xeb92, fontFamily: 'iconfont'); + static const IconData icon_addperson = + IconData(0xeb93, fontFamily: 'iconfont'); + static const IconData icon_boss = IconData(0xeb94, fontFamily: 'iconfont'); + static const IconData icon_airplay = IconData(0xeb95, fontFamily: 'iconfont'); + static const IconData icon_calendar = + IconData(0xeb96, fontFamily: 'iconfont'); + static const IconData icon_attestation = + IconData(0xeb97, fontFamily: 'iconfont'); + static const IconData icon_camera = IconData(0xeb98, fontFamily: 'iconfont'); + static const IconData icon_certificate_fil = + IconData(0xeb99, fontFamily: 'iconfont'); + static const IconData icon_coinpurse_line = + IconData(0xeb9a, fontFamily: 'iconfont'); + static const IconData icon_collect = IconData(0xeb9b, fontFamily: 'iconfont'); + static const IconData icon_compile = IconData(0xeb9c, fontFamily: 'iconfont'); +} diff --git a/lib/ui/widgets/common/list/article_item.dart b/lib/ui/widgets/common/list/article_item.dart new file mode 100644 index 0000000..3dcec2c --- /dev/null +++ b/lib/ui/widgets/common/list/article_item.dart @@ -0,0 +1,93 @@ +import 'package:base_app/models/article_model.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; + +import '../progress_view_widget.dart'; + +// 文章列表项 list_page用 +class ArticleItem extends StatelessWidget { + const ArticleItem(this.model, {this.labelId, Key key // 是否是主页 + }) + : super(key: key); + final String labelId; // labelId + final ArticleModel model; // 模型 + + @override + Widget build(BuildContext context) { + return new InkWell( + onTap: () { + NavigatorUtil.pushWeb(context, title: model.title, url: model.link); + }, + child: new Container( + height: 160.0, + padding: EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 10), + child: new Row( + children: [ + new Expanded( + child: new Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + new Text( + model.title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyles.listTitle, + ), + Gaps.vGap10, + new Expanded( + flex: 1, + child: new Text( + model.desc, + maxLines: 3, + softWrap: true, + overflow: TextOverflow.ellipsis, + style: TextStyles.listContent, + ), + ), + Gaps.vGap5, + new Row( + children: [ + Gaps.hGap10, + new Text( + model.author, + style: TextStyles.listExtra, + ), + Gaps.hGap10, + new Text( + Utils.getTimeLine(context, model.publishTime), + style: TextStyles.listExtra, + ), + ], + ) + ], + )), + new Container( + width: 72, + alignment: Alignment.center, + margin: EdgeInsets.only(left: 10.0), + child: new CachedNetworkImage( + width: 72, + height: 128, + fit: BoxFit.fill, + imageUrl: model.envelopePic, + placeholder: (BuildContext context, String url) { + return new ProgressView(); + }, + errorWidget: + (BuildContext context, String url, Object error) { + return new Icon(Icons.error); + }, + ), + ) + ], + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(width: 0.33, color: Colours.divider)))), + ); + } +} diff --git a/lib/ui/widgets/common/list/header_item.dart b/lib/ui/widgets/common/list/header_item.dart new file mode 100644 index 0000000..3884369 --- /dev/null +++ b/lib/ui/widgets/common/list/header_item.dart @@ -0,0 +1,76 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/res/strings.dart'; +import 'package:base_app/utils/utils.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; + +class HeaderItem extends StatelessWidget { + const HeaderItem( + {this.margin, + this.titleColor, + this.leftIcon, + this.titleId: Ids.titleRepos, + this.title, + this.extraId: Ids.more, + this.extra, + this.rightIcon, + this.onTap, + Key key}) + : super(key: key); + + final EdgeInsetsGeometry margin; // 边距 + final Color titleColor; // 标题颜色 + final IconData leftIcon; // 左边的icon + final String titleId; // 标题id, 对应Ids中的字典 + final String title; // 标题 + final String extraId; //其他文字id, 对应Ids中字典 + final String extra; // 其他文字 + final IconData rightIcon; // 右边的icon + final GestureTapCallback onTap; // 点击事件 + + @override + Widget build(BuildContext context) { + return new Container( + height: 56.0, + margin: margin ?? EdgeInsets.only(top: 0.0), + child: new ListTile( + onTap: onTap, + title: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Icon( + leftIcon ?? Icons.whatshot, + color: titleColor ?? Colors.blueAccent, + ), + Gaps.hGap10, + new Expanded( + child: new Text( + title ?? IntlUtil.getString(context, titleId), + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor ?? Colors.blueAccent, + fontSize: Utils.getTitleFontSize( + title ?? IntlUtil.getString(context, titleId))), + )) + ], + ), + trailing: new Row( + mainAxisSize: MainAxisSize.min, + children: [ + new Text( + extra ?? IntlUtil.getString(context, extraId), + style: TextStyle(color: Colors.grey, fontSize: 14), + ), + new Icon( + rightIcon ?? Icons.keyboard_arrow_right, + color: Colors.grey, + ), + ], + )), + decoration: new BoxDecoration( + //new Border.all(width: 0.33, color: Colours.divider) + border: new Border( + bottom: new BorderSide(width: 0.33, color: Colours.divider))), + ); + } +} diff --git a/lib/ui/widgets/common/list/refresh_scaffold.dart b/lib/ui/widgets/common/list/refresh_scaffold.dart new file mode 100644 index 0000000..967f40b --- /dev/null +++ b/lib/ui/widgets/common/list/refresh_scaffold.dart @@ -0,0 +1,115 @@ +import 'package:base_app/ui/widgets/common/list/status_views.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/material.dart'; +import 'package:pull_to_refresh/pull_to_refresh.dart'; + +typedef void OnLoadMore(bool up); +typedef OnRefreshCallback = Future Function({bool isReload}); + +class RefreshScaffold extends StatefulWidget { + const RefreshScaffold( + {Key key, + this.labelId, + this.loadStatus, + @required this.controller, + this.enablePullUp: true, + this.onRefresh, + this.onLoadMore, + this.child, + this.itemCount, + this.itemBuilder}) + : super(key: key); + + final String labelId; + final int loadStatus; + final RefreshController controller; + final bool enablePullUp; + final OnRefreshCallback onRefresh; + final OnLoadMore onLoadMore; + final Widget child; + final int itemCount; + final IndexedWidgetBuilder itemBuilder; + + @override + State createState() { + return new RefreshScaffoldState(); + } +} + +/// with AutomaticKeepAliveClientMixin +class RefreshScaffoldState extends State + with AutomaticKeepAliveClientMixin { + bool isShowFloatBtn = false; + + @override + void initState() { + super.initState(); +// LogUtil.e("RefreshScaffold initState......" + widget.labelId); + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.controller.scrollController.addListener(() { + int offset = widget.controller.scrollController.offset.toInt(); + if (offset < 480 && isShowFloatBtn) { + isShowFloatBtn = false; + setState(() {}); + } else if (offset > 480 && !isShowFloatBtn) { + isShowFloatBtn = true; + setState(() {}); + } + }); + }); + } + + Widget buildFloatingActionButton() { + if (widget.controller.scrollController == null || + widget.controller.scrollController.offset < 480) { + return null; + } + + return new FloatingActionButton( + heroTag: widget.labelId, + backgroundColor: Theme.of(context).primaryColor, + child: Icon( + Icons.keyboard_arrow_up, + ), + onPressed: () { + //_controller.scrollTo(0.0); + widget.controller.scrollController.animateTo(0.0, + duration: new Duration(milliseconds: 300), curve: Curves.linear); + }); + } + + @override + Widget build(BuildContext context) { +// LogUtil.e("RefreshScaffold build...... " + widget.labelId); + super.build(context); + return new Scaffold( + body: new Stack( + children: [ + new RefreshIndicator( + child: new SmartRefresher( + controller: widget.controller, + enablePullDown: false, + enablePullUp: widget.enablePullUp, + enableOverScroll: false, + onRefresh: widget.onLoadMore, + child: widget.child ?? + new ListView.builder( + itemCount: widget.itemCount, + itemBuilder: widget.itemBuilder, + )), + onRefresh: widget.onRefresh), + new StatusViews( + widget.loadStatus, + onTap: () { + LogUtil.e("ProgressViews onRefresh......"); + widget.onRefresh(isReload: true); + }, + ), + ], + ), + floatingActionButton: buildFloatingActionButton()); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/ui/widgets/common/list/status_views.dart b/lib/ui/widgets/common/list/status_views.dart new file mode 100644 index 0000000..0c1cdb1 --- /dev/null +++ b/lib/ui/widgets/common/list/status_views.dart @@ -0,0 +1,85 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/util_index.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +import '../progress_view_widget.dart'; + +class StatusViews extends StatelessWidget { + const StatusViews(this.status, {Key key, this.onTap}) : super(key: key); + final int status; + final GestureTapCallback onTap; + + @override + Widget build(BuildContext context) { + switch (status) { + case LoadStatus.fail: + return new Container( + width: double.infinity, + child: new Material( + color: Colors.white, + child: new InkWell( + onTap: () { + onTap(); + }, + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_network_error"), + width: 100, + height: 100, + ), + Gaps.vGap10, + new Text( + "网络出问题了~ 请您查看网络设置", + style: TextStyles.listContent, + ), + Gaps.vGap5, + new Text( + "点击屏幕,重新加载", + style: TextStyles.listContent, + ), + ], + ), + ), + ), + ); + break; + case LoadStatus.loading: + return new Container( + alignment: Alignment.center, + color: Colours.gray_f0, + child: new ProgressView(), + ); + break; + case LoadStatus.empty: + return new Container( + color: Colors.white, + width: double.infinity, + child: new Center( + child: new Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + new Image.asset( + Utils.getImgPath("ic_data_empty"), + width: 60, + height: 60, + ), + Gaps.vGap10, + new Text( + "空空如也~", + style: TextStyles.listContent, + ), + ], + ), + ), + ); + break; + default: + return Container(); + break; + } + } +} diff --git a/lib/ui/widgets/common/progress_view_widget.dart b/lib/ui/widgets/common/progress_view_widget.dart new file mode 100644 index 0000000..bf31bda --- /dev/null +++ b/lib/ui/widgets/common/progress_view_widget.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; + +// 进度旋转 +class ProgressView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return new Center( + child: new SizedBox( + width: 24.0, + height: 24.0, + child: new CircularProgressIndicator( + strokeWidth: 2.0, + ), + ), + ); + } +} diff --git a/lib/ui/widgets/common/route/fadeRoute.dart b/lib/ui/widgets/common/route/fadeRoute.dart new file mode 100644 index 0000000..09cda1e --- /dev/null +++ b/lib/ui/widgets/common/route/fadeRoute.dart @@ -0,0 +1,21 @@ +import 'package:flutter/widgets.dart'; + +///FadeRoute是自定义的切换过度动画(渐隐渐现) +class FadeRoute extends PageRouteBuilder { + final Widget page; + FadeRoute({this.page}): super( + pageBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) =>page,transitionsBuilder: ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) =>FadeTransition( + opacity: animation, + child: child, + ), + ); +} \ No newline at end of file diff --git a/lib/ui/widgets/common/route/popRoute.dart b/lib/ui/widgets/common/route/popRoute.dart new file mode 100644 index 0000000..e779cd1 --- /dev/null +++ b/lib/ui/widgets/common/route/popRoute.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +class PopRoute extends PopupRoute{ + final Duration _duration = Duration(milliseconds: 300); + Widget child; + + PopRoute({@required this.child}); + + @override + Color get barrierColor => null; + + @override + bool get barrierDismissible => true; + + @override + String get barrierLabel => null; + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + return child; + } + + @override + Duration get transitionDuration => _duration; + +} \ No newline at end of file diff --git a/lib/ui/widgets/common/web_scaffold.dart b/lib/ui/widgets/common/web_scaffold.dart new file mode 100644 index 0000000..3c7efe2 --- /dev/null +++ b/lib/ui/widgets/common/web_scaffold.dart @@ -0,0 +1,173 @@ +import 'package:base_app/res/index.dart'; +import 'package:base_app/utils/navigator_util.dart'; +import 'package:fluintl/fluintl.dart'; +import 'package:flutter/material.dart'; +import 'package:share/share.dart'; +import 'package:webview_flutter/webview_flutter.dart'; + +import 'button/likebtn/like_button.dart'; + +class WebScaffold extends StatefulWidget { + const WebScaffold({ + Key key, + this.title, + this.titleId, + this.url, + }) : super(key: key); + + final String title; + final String titleId; + final String url; + + @override + State createState() { + return new WebScaffoldState(); + } +} + +class WebScaffoldState extends State { +// WebViewController _webViewController; +// bool _isShowFloatBtn = false; + + void _onPopSelected(String value) { + String _title = widget.title ?? IntlUtil.getString(context, widget.titleId); + switch (value) { + case "browser": // 浏览 + NavigatorUtil.launchInBrowser(widget.url, title: _title); + break; + case "collection": // 收藏 + break; + case "share": // 分享 + String _url = widget.url; + Share.share('$_title : $_url'); + break; + default: + break; + } + } + + @override + Widget build(BuildContext context) { + return new Scaffold( + appBar: new AppBar( + title: new Text( + widget.title ?? IntlUtil.getString(context, widget.titleId), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + centerTitle: true, + actions: [ + LikeButton( + width: 56.0, + duration: Duration(milliseconds: 500), + ), +// new IconButton(icon: new Icon(Icons.more_vert), onPressed: () {}), + new PopupMenuButton( + padding: const EdgeInsets.all(0.0), + onSelected: _onPopSelected, + itemBuilder: (BuildContext context) => >[ + new PopupMenuItem( + value: "browser", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.language, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '浏览器打开', + style: TextStyles.listContent, + ) + ], + ), + ))), +// new PopupMenuItem( +// value: "collection", +// child: ListTile( +// contentPadding: EdgeInsets.all(0.0), +// dense: false, +// title: new Container( +// alignment: Alignment.center, +// child: new Row( +// children: [ +// Icon( +// Icons.collections, +// color: Colours.gray_66, +// size: 22.0, +// ), +// Gaps.hGap10, +// Text( +// '收藏', +// style: TextStyles.listContent, +// ) +// ], +// ), +// ))), + new PopupMenuItem( + value: "share", + child: ListTile( + contentPadding: EdgeInsets.all(0.0), + dense: false, + title: new Container( + alignment: Alignment.center, + child: new Row( + children: [ + Icon( + Icons.share, + color: Colours.gray_66, + size: 22.0, + ), + Gaps.hGap10, + Text( + '分享', + style: TextStyles.listContent, + ) + ], + ), + ))), + ]) + ], + ), + body: new WebView( + onWebViewCreated: (WebViewController webViewController) { +// _webViewController = webViewController; +// _webViewController.addListener(() { +// int _scrollY = _webViewController.scrollY.toInt(); +// if (_scrollY < 480 && _isShowFloatBtn) { +// _isShowFloatBtn = false; +// setState(() {}); +// } else if (_scrollY > 480 && !_isShowFloatBtn) { +// _isShowFloatBtn = true; +// setState(() {}); +// } +// }); + }, + initialUrl: widget.url, + javascriptMode: JavascriptMode.unrestricted, + ), +// floatingActionButton: _buildFloatingActionButton(), + ); + } + +// Widget _buildFloatingActionButton() { +// if (_webViewController == null || _webViewController.scrollY < 480) { +// return null; +// } +// return new FloatingActionButton( +// heroTag: widget.title ?? widget.titleId, +// backgroundColor: Theme.of(context).primaryColor, +// child: Icon( +// Icons.keyboard_arrow_up, +// ), +// onPressed: () { +// _webViewController.scrollTop(); +// }); +// } +} diff --git a/lib/ui/widgets/login_page/login_item_widget.dart b/lib/ui/widgets/login_page/login_item_widget.dart new file mode 100644 index 0000000..58a8778 --- /dev/null +++ b/lib/ui/widgets/login_page/login_item_widget.dart @@ -0,0 +1,96 @@ +import 'package:base_app/res/index.dart'; +import 'package:flutter/material.dart'; + +/// 登录项 +class LoginItem extends StatefulWidget { + final IconData prefixIcon; // 前方icon + final bool hasSuffixIcon; // 是否要后面的icon + final String hintText; // 提示文字 + final bool autoFocus; // 自动聚焦 + final TextInputType keyboardType; // 键盘类型 + final int maxLength; // 最大程度 + final bool maxLengthEnforced; // 当长度达到限制长度时,是否强制组织输入 + final TextInputAction textInputAction; // 输入action + final TextEditingController controller; // controller + final FocusNode focusNode; //focusNode + final VoidCallback onEditingComplete; // 输入完毕后的回调 + + const LoginItem( + {Key key, + this.prefixIcon, + this.hasSuffixIcon = false, + this.autoFocus = false, + this.keyboardType = TextInputType.text, + this.hintText, + this.maxLength, + this.maxLengthEnforced = true, + this.textInputAction, + this.controller, + this.focusNode, + this.onEditingComplete}) + : super(key: key); + + @override + State createState() { + return LoginItemState(); + } +} + +class LoginItemState extends State { + bool _obscureText; // 是否隐藏原始文字 // 密码用 + + @override + void initState() { + super.initState(); + _obscureText = widget.hasSuffixIcon; + } + + @override + Widget build(BuildContext context) { + return new Row( + children: [ + new IconButton( + iconSize: 28, + icon: new Icon( + widget.prefixIcon, + color: Theme.of(context).primaryColor, + ), + onPressed: () {}), + Gaps.hGap5, + new Expanded( + child: new TextField( + textInputAction: widget.textInputAction, + focusNode: widget.focusNode, + onEditingComplete: widget.onEditingComplete, + obscureText: _obscureText, + controller: widget.controller, + maxLength: widget.maxLength, + maxLengthEnforced: widget.maxLengthEnforced, + style: new TextStyle(color: Colours.gray_66, fontSize: 14), + decoration: new InputDecoration( + hintText: widget.hintText, + hintStyle: new TextStyle(color: Colours.gray_99, fontSize: 14), + suffixIcon: widget.hasSuffixIcon + ? new IconButton( + icon: new Icon( + _obscureText + ? Icons.visibility + : Icons.visibility_off, + color: Colours.gray_66, + ), + onPressed: () { + setState(() { + _obscureText = !_obscureText; + }); + }) + : null, + focusedBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + enabledBorder: new UnderlineInputBorder( + borderSide: new BorderSide(color: Colours.green_de)), + )), + ), + ], + ); + } +} diff --git a/lib/utils/encrypt_helper.dart b/lib/utils/encrypt_helper.dart new file mode 100644 index 0000000..caf7196 --- /dev/null +++ b/lib/utils/encrypt_helper.dart @@ -0,0 +1,30 @@ +import 'package:encrypt/encrypt.dart'; +import 'package:pointycastle/asymmetric/api.dart'; +import 'dart:async'; +import 'package:flutter/services.dart' show rootBundle; + +/// RSA加密工具 +final parser = RSAKeyParser(); + +class EncryptHelper { + /// 加密 + ///[src] 待加密字符串 + static Future encode(String src) async { + String publicKeyString = await rootBundle.loadString('keys/public_key.pem'); + RSAPublicKey publicKey = parser.parse(publicKeyString); + final encrypter = Encrypter(RSA(publicKey: publicKey)); + return encrypter.encrypt(src).base64; + } + + /// 解密 + /// [decoded] 待解密字符串 + static Future decode(String decoded) async { + String privateKeyString = + await rootBundle.loadString('keys/private_key.pem'); + + final privateKey = parser.parse(privateKeyString); + + final encrypter = Encrypter(RSA(privateKey: privateKey)); + return encrypter.decrypt(Encrypted.fromBase64(decoded)); + } +} diff --git a/lib/utils/http_utils.dart b/lib/utils/http_utils.dart new file mode 100644 index 0000000..319ca63 --- /dev/null +++ b/lib/utils/http_utils.dart @@ -0,0 +1,30 @@ +import 'package:base_app/models/common/splash_model.dart'; +import 'package:base_app/models/common/version_model.dart'; + +/// 模拟网络请求数据 +class HttpUtils { + Future getSplash() { + return Future.delayed(Duration(milliseconds: 500), () { + return SplashModel( + title: 'Flutter 常用工具类库', + content: 'Flutter 常用工具类库', + url: 'https://www.jianshu.com/p/425a7ff9d66e', + imgUrl: + 'https://raw.githubusercontent.com/Sky24n/LDocuments/master/AppImgs/flutter_common_utils_a.png', + ); + }); + } + + /// 该地址可能无法下载,请自行更换可测试apk地址。 + Future getVersion() async { + return Future.delayed(Duration(milliseconds: 500), () { + return VersionModel( + title: '有新版本v1.1.0,快去更新吧!', + content: '1.基础库升级 | 2.修复OPPO R15详情页问题 | 3.一些优化~', + url: + 'https://raw.githubusercontent.com/Sky24n/Doc/master/apks/flutter_wanandroid.apk', + version: '1.0.0', + ); + }); + } +} diff --git a/lib/utils/login_utils.dart b/lib/utils/login_utils.dart new file mode 100644 index 0000000..af31546 --- /dev/null +++ b/lib/utils/login_utils.dart @@ -0,0 +1,47 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/data/protocol/user_model.dart'; +import 'package:base_app/data/repository/user_repository.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flustars/flustars.dart'; + +/// 登录工具类 +class LoginUtils { + /// 判断用户是否已登录 + static Future isLogin() async { + // 1. 先判断token是否在 + bool hasToken = + ObjectUtil.isNotEmpty(SpUtil.getString(BaseConstant.keyAppToken)); + if (hasToken) { + // 2.用token去获取用户信息,有信息认为已登录,否则为未登录 + UserRepository userRepository = new UserRepository(); + UserModel user = await userRepository.getUserInfo(); + if (user == null) { + // 未登录的尝试自动登录,返回自动登录结果 + return await autoLogin(); + } else { + return true; + } + } else { + return hasToken; + } + } + + // 自动登录 + static Future autoLogin() async { + // 取用户名和密码自动登录 + String username = SpUtil.getString(BaseConstant.keyAccount); + String password = SpUtil.getString(BaseConstant.keyPassword); + UserRepository userRepository = new UserRepository(); + LoginReq req = new LoginReq(username, password); + try { + UserModel model = await userRepository.login(req); + if (model != null) { + return true; + } else { + return false; + } + } catch (error) { + return false; + } + } +} diff --git a/lib/utils/map_utils.dart b/lib/utils/map_utils.dart new file mode 100644 index 0000000..dc6029d --- /dev/null +++ b/lib/utils/map_utils.dart @@ -0,0 +1,72 @@ +import 'dart:math'; + +import 'package:amap_map_fluttify/amap_map_fluttify.dart'; + +/// 地图工具类 +class MapUtils { + ///计算两点距离 + ///[start] 第一个点坐标[lng,lat] + ///[end]第二个点坐标[lng,lat] + static double calculateDistance(start, end) { + if ((start != null) || (end != null)) { + double d1 = 0.01745329251994329; + double d2 = start[0]; //lng + double d3 = start[1]; //lat + double d4 = end[0]; //lng + double d5 = end[1]; //lat + d2 *= d1; + d3 *= d1; + d4 *= d1; + d5 *= d1; + double d6 = sin(d2); + double d7 = sin(d3); + double d8 = cos(d2); + double d9 = cos(d3); + double d10 = sin(d4); + double d11 = sin(d5); + double d12 = cos(d4); + double d13 = cos(d5); + List arrayOfDouble1 = List(3); + List arrayOfDouble2 = List(3); + arrayOfDouble1[0] = (d9 * d8); + arrayOfDouble1[1] = (d9 * d6); + arrayOfDouble1[2] = d7; + arrayOfDouble2[0] = (d13 * d12); + arrayOfDouble2[1] = (d13 * d10); + arrayOfDouble2[2] = d11; + double d14 = sqrt((arrayOfDouble1[0] - arrayOfDouble2[0]) * + (arrayOfDouble1[0] - arrayOfDouble2[0]) + + (arrayOfDouble1[1] - arrayOfDouble2[1]) * + (arrayOfDouble1[1] - arrayOfDouble2[1]) + + (arrayOfDouble1[2] - arrayOfDouble2[2]) * + (arrayOfDouble1[2] - arrayOfDouble2[2])); + print((asin(d14 / 2.0) * 12742001.579854401)); + return (asin(d14 / 2.0) * 12742001.579854401).abs(); + } else { + return 0.0; + } + } +} + +/// 获取随机坐标 +mixin NextLatLng { + final random = Random(); + + LatLng getNextLatLng({LatLng center}) { + center ??= LatLng(39.90960, 116.397228); + return LatLng( + center.latitude + random.nextDouble(), + center.longitude + random.nextDouble(), + ); + } + + List getNextBatchLatLng(int count) { + return [ + for (int i = 0; i < count; i++) + LatLng( + 39.90960 + random.nextDouble() * 4, + 116.397228 + random.nextDouble() * 4, + ) + ]; + } +} diff --git a/lib/utils/navigator_util.dart b/lib/utils/navigator_util.dart new file mode 100644 index 0000000..00c6bc1 --- /dev/null +++ b/lib/utils/navigator_util.dart @@ -0,0 +1,52 @@ +import 'package:base_app/ui/pages/user/user_login_page.dart'; +import 'package:base_app/ui/widgets/common/web_scaffold.dart'; +import 'package:base_app/utils/login_utils.dart'; +import 'package:flustars/flustars.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class NavigatorUtil { + // 打开页面 + static void pushPage( + BuildContext context, + Widget page, { + String pageName, + bool needLogin = false, + }) async { + if (context == null || page == null) return; + bool isLogin = await LoginUtils.isLogin(); + if (needLogin && isLogin == false) { + pushPage(context, UserLoginPage()); + return; + } + Navigator.push( + context, new CupertinoPageRoute(builder: (ctx) => page)); + } + + // 打开网页 + static void pushWeb(BuildContext context, + {String title, String titleId, String url}) { + if (context == null || ObjectUtil.isEmpty(url)) return; + if (url.endsWith(".apk")) { + launchInBrowser(url, title: title ?? titleId); + } else { + Navigator.push( + context, + new CupertinoPageRoute( + builder: (ctx) => new WebScaffold( + title: title, + titleId: titleId, + url: url, + ))); + } + } + + // 打开浏览器 + static Future launchInBrowser(String url, {String title}) async { + if (await canLaunch(url)) { + await launch(url, forceSafariVC: false, forceWebView: false); + } else { + throw 'Could not launch $url'; + } + } +} diff --git a/lib/utils/permission_util.dart b/lib/utils/permission_util.dart new file mode 100644 index 0000000..6e75801 --- /dev/null +++ b/lib/utils/permission_util.dart @@ -0,0 +1,15 @@ +import 'package:oktoast/oktoast.dart'; +import 'package:permission_handler/permission_handler.dart'; + +/// 请求权限工具 + +/// 请求位置权限 +Future reqPositionPermission() async { + final status = await Permission.location.request(); + if (status == PermissionStatus.granted) { + return true; + } else { + showToast('需要定位权限,请去设置中开启'); + return false; + } +} diff --git a/lib/utils/route_util.dart b/lib/utils/route_util.dart new file mode 100644 index 0000000..3d8a6a6 --- /dev/null +++ b/lib/utils/route_util.dart @@ -0,0 +1,22 @@ +import 'package:base_app/common/common.dart'; +import 'package:flutter/material.dart'; + +class RouteUtil { + // 去主页 + static void goMain(BuildContext context) { + pushReplacementNamed(context, BaseConstant.routeMain); + } + + // 去登录页 + static void goLogin(BuildContext context) { + pushReplacementNamed(context, BaseConstant.routeLogin); + } + + static void pushNamed(BuildContext context, String pageName) { + Navigator.of(context).pushNamed(pageName); + } + + static void pushReplacementNamed(BuildContext context, String pageName) { + Navigator.of(context).pushReplacementNamed(pageName); + } +} diff --git a/lib/utils/util_index.dart b/lib/utils/util_index.dart new file mode 100644 index 0000000..b240611 --- /dev/null +++ b/lib/utils/util_index.dart @@ -0,0 +1,9 @@ +export 'navigator_util.dart'; +export 'login_utils.dart'; +export 'http_utils.dart'; +export 'encrypt_helper.dart'; +export 'map_utils.dart'; +export 'navigator_util.dart'; +export 'route_util.dart'; +export 'utils.dart'; +export 'permission_util.dart'; diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart new file mode 100644 index 0000000..f2f8f38 --- /dev/null +++ b/lib/utils/utils.dart @@ -0,0 +1,152 @@ +import 'package:base_app/common/common.dart'; +import 'package:base_app/res/index.dart'; +import 'package:common_utils/common_utils.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; +import 'dart:convert' as convert; + +/// 工具类 +class Utils { + // 是否需要登录 + static bool isNeedLogin(String pageId) { + return false; + } + + /// 显示提示信息,在屏幕下方 + static void showSnackBar(BuildContext context, String msg) { + Scaffold.of(context).showSnackBar( + SnackBar(content: Text("$msg")), + ); + } + + // 加载文本资源 + Future loadAsset(String filename) async { + return await rootBundle.loadString('assets/data/$filename'); + } + + /// 获取图片路径 + /// [name] 图片名称 不含后缀,assets/images文件夹下地图图片 + /// [format] 图片格式(后缀,如png,jpg等) + static String getImgPath(String name, {String format: 'png'}) { + return 'assets/images/$name.$format'; + } + + /// 获取文件名称 + /// [urlPath] 文件路径 + static String getFileName(String urlPath) { + if (ObjectUtil.isEmpty(urlPath)) return ''; + List listStr = urlPath.split("/"); + String name = listStr[listStr.length - 1]; + return name; + } + + /// 获取字符串对应拼音的首字母的大写字母 + /// [str] 待处理字符串 + static String getPinyin(String str) { + return PinyinHelper.getShortPinyin(str).substring(0, 1).toUpperCase(); + } + + /// 获取圆圈的背景 + static Color getCircleBg(String str) { + String pinyin = getPinyin(str); + return getCircleAvatarBg(pinyin); + } + + /// 获取头像背景颜色 + /// [key] 对照表中的key + static Color getCircleAvatarBg(String key) { + return circleAvatarMap[key]; + } + + static Color getChipBgColor(String name) { + String pinyin = PinyinHelper.getFirstWordPinyin(name); + pinyin = pinyin.substring(0, 1).toUpperCase(); + return nameToColor(pinyin); + } + + static Color nameToColor(String name) { + // assert(name.length > 1); + final int hash = name.hashCode & 0xffff; + final double hue = (360.0 * hash / (1 << 15)) % 360.0; + return HSVColor.fromAHSV(1.0, hue, 0.4, 0.90).toColor(); + } + + static String getTimeLine(BuildContext context, int timeMillis) { +// LogUtil.e("countryCode: " + +// Localizations.localeOf(context).countryCode + +// " languageCode: " + +// Localizations.localeOf(context).languageCode); + return TimelineUtil.format(timeMillis, + locale: Localizations.localeOf(context).languageCode, + dayFormat: DayFormat.Common); + } + + /// 计算标题字号 + /// [title] 标题 + static double getTitleFontSize(String title) { + // 小于10个字,18号字体 + if (ObjectUtil.isEmpty(title) || title.length < 10) { + return 18.0; + } + int count = 0; + List list = title.split(""); + for (int i = 0, length = list.length; i < length; i++) { + String ss = list[i]; + if (RegexUtil.isZh(ss)) { + count++; + } + } + //10个汉字或16个字符以上,14号字 + return (count >= 10 || title.length > 16) ? 14.0 : 18.0; + } + + /// 判断升级状态,如果远程版本小于等于当前按本,返回0 不升级, + /// 如果返回 1 升级 + /// > x 强升 + static int getUpdateStatus(String version, {String local}) { + if (ObjectUtil.isEmpty(version)) return 0; + String locVersion = local ?? AppConfig.version; + int remote = int.tryParse(version.replaceAll('.', '')); + int loc = int.tryParse(locVersion.replaceAll('.', '')); + if (remote <= loc) { + return 0; + } else { + return remote - loc; + } + } + + /// 获取加载状态 + static int getLoadStatus(bool hasError, List data) { + if (hasError) return LoadStatus.fail; + if (data == null) { + // data为空,加载中 + return LoadStatus.loading; + } else if (data.isEmpty) { + // data为空数组,返回空 + return LoadStatus.empty; + } else { + // + return LoadStatus.success; + } + } + + /// 字符串转列表 + /// [str] 待转字符串 如:[1,2,3,4,5] + static List strToList(String str) { + if (str == '') { + str = "[]"; + } + List list = convert.jsonDecode(str); + print(list); + return list; + } + + /// 列表转字符串 + /// [list] 待转列表 + static String listToStr(List list) { + String str = convert.jsonEncode(list); + print(str); + return str; + } +} diff --git a/lib/utils/version_util.dart b/lib/utils/version_util.dart new file mode 100644 index 0000000..1b92ecc --- /dev/null +++ b/lib/utils/version_util.dart @@ -0,0 +1,98 @@ +import 'dart:io'; + +import 'package:dio/dio.dart'; +import 'package:flustars/flustars.dart'; +import 'package:install_apk_plugin/install_apk_plugin.dart'; + +import 'utils.dart'; + +/// 版本更新工具类 +class VersionUtil { + static final VersionUtil _singleton = VersionUtil._init(); + + static Dio _dio = Dio(); + + List listeners = List(); + + bool isDownload = false; + + factory VersionUtil() { + return _singleton; + } + + VersionUtil._init(); + + void downloadApk(String urlPath, String appId) async { + if (isDownload == true || ObjectUtil.isEmpty(urlPath)) return; + try { + await DirectoryUtil.getInstance(); + String apkDirPath = DirectoryUtil.getStoragePath(category: 'Download'); + LogUtil.e("apkDirPath: $apkDirPath"); + Directory apkDir = DirectoryUtil.createDirSync(apkDirPath); + + String apkName = Utils.getFileName(urlPath); + String apkPath = '$apkDirPath/$apkName'; + String apkTempPath = '$apkDirPath/temp_$apkName'; + + LogUtil.e("apkPath: $apkPath"); + LogUtil.e("apkTempPath: $apkTempPath"); + + File file = File(apkPath); + if (file.existsSync()) { + _install(apkPath, appId); + isDownload = false; + listeners.forEach((listener) { + listener(1, 1); + }); + return; + } + isDownload = true; + Response response = await _dio.download( + urlPath, + apkTempPath, + onProgress: (int count, int total) { + LogUtil.e( + "onReceiveProgress total: $total, count: $count, prect: ${count / total}"); + listeners.forEach((listener) { + listener(count, total); + }); + if (count == total) { + isDownload = false; + File file = File(apkTempPath); + File fileNew = file.copySync(apkPath); + file.deleteSync(); + _install(apkPath, appId); + } + }, + ); + } catch (e) { + LogUtil.e("download apk error: ${e?.toString()}"); + isDownload = false; + listeners.forEach((listener) { + listener(-1, 1); + }); + } + } + + void _install(String filePath, String appId) { + InstallPlugin.installApk(filePath, appId).then((result) { + LogUtil.e('install apk $result'); + }).catchError((error) { + LogUtil.e('install apk error: $error'); + }); + } + + void addListener(OnDownloadProgress listener) { + if (listener == null) return; + if (!listeners.contains(listener)) { + listeners.add(listener); + } + } + + void removeListener(OnDownloadProgress listener) { + if (listener == null) return; + if (listeners.contains(listener)) { + listeners.remove(listener); + } + } +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..74cac3b --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,640 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + amap_core_fluttify: + dependency: transitive + description: + name: amap_core_fluttify + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.9.5" + amap_map_fluttify: + dependency: "direct main" + description: + name: amap_map_fluttify + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.24.0+3" + archive: + dependency: transitive + description: + name: archive + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.13" + args: + dependency: transitive + description: + name: args + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.6.0" + asn1lib: + dependency: transitive + description: + name: asn1lib + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.5" + async: + dependency: transitive + description: + name: async + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.1" + azlistview: + dependency: "direct main" + description: + name: azlistview + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.2" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.3" + clock: + dependency: transitive + description: + name: clock + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.14.12" + common_utils: + dependency: transitive + description: + name: common_utils + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.2.1" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.1" + cookie_jar: + dependency: transitive + description: + name: cookie_jar + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.8" + core_location_fluttify: + dependency: transitive + description: + name: core_location_fluttify + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.4" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.4" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.3" + decimal: + dependency: transitive + description: + name: decimal + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.5" + dio: + dependency: "direct main" + description: + name: dio + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.13" + encrypt: + dependency: "direct main" + description: + name: encrypt + url: "https://pub.flutter-io.cn" + source: hosted + version: "4.0.2" + file: + dependency: transitive + description: + name: file + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.2.1" + fluintl: + dependency: "direct main" + description: + name: fluintl + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.3" + flukit: + dependency: "direct main" + description: + name: flukit + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + flustars: + dependency: "direct main" + description: + name: flustars + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.3" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.3" + flutter_localizations: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.8" + 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" + foundation_fluttify: + dependency: transitive + description: + name: foundation_fluttify + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.8.11" + http: + dependency: transitive + description: + name: http + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.12.2" + http_parser: + dependency: transitive + description: + name: http_parser + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.1.4" + image: + dependency: transitive + description: + name: image + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.12" + image_picker: + dependency: "direct main" + description: + name: image_picker + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.7+4" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + install_apk_plugin: + dependency: "direct main" + description: + name: install_apk_plugin + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" + intl: + dependency: transitive + description: + name: intl + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.16.1" + latlng: + dependency: transitive + description: + name: latlng + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.2" + lpinyin: + dependency: "direct main" + description: + name: lpinyin + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.9" + matcher: + dependency: transitive + description: + name: matcher + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.12.6" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.8" + oktoast: + dependency: "direct main" + description: + name: oktoast + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.3.2" + path: + dependency: transitive + description: + name: path + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.6.4" + path_provider: + dependency: transitive + description: + name: path_provider + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.6.11" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1+2" + path_provider_macos: + dependency: transitive + description: + name: path_provider_macos + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.4+3" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + pedantic: + dependency: transitive + description: + name: pedantic + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.9.0" + permission_handler: + dependency: "direct main" + description: + name: permission_handler + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.0.1+1" + permission_handler_platform_interface: + dependency: transitive + description: + name: permission_handler_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.1" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.0" + photo_view: + dependency: "direct main" + description: + name: photo_view + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.9.2" + platform: + dependency: transitive + description: + name: platform + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.1" + platform_detect: + dependency: transitive + description: + name: platform_detect + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.4.0" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + pointycastle: + dependency: transitive + description: + name: pointycastle + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2" + process: + dependency: transitive + description: + name: process + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.13" + pub_semver: + dependency: transitive + description: + name: pub_semver + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.4.4" + pull_to_refresh: + dependency: "direct main" + description: + name: pull_to_refresh + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.6" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.1.3" + rational: + dependency: transitive + description: + name: rational + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.8" + rxdart: + dependency: "direct main" + description: + name: rxdart + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.22.6" + share: + dependency: "direct main" + description: + name: share + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.6.4+3" + shared_preferences: + dependency: transitive + description: + name: shared_preferences + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.5.8" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.2+1" + shared_preferences_macos: + dependency: transitive + description: + name: shared_preferences_macos + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1+10" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.4" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.2+7" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.7.0" + sp_util: + dependency: transitive + description: + name: sp_util + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.1" + sqflite: + dependency: "direct main" + description: + name: sqflite + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.3.1" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.2+1" + stack_trace: + dependency: transitive + description: + name: stack_trace + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.9.3" + stream_channel: + dependency: transitive + description: + name: stream_channel + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.5" + synchronized: + dependency: transitive + description: + name: synchronized + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.0+2" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.0" + test_api: + dependency: transitive + description: + name: test_api + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.15" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.1.6" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + url: "https://pub.flutter-io.cn" + source: hosted + version: "5.5.0" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1+1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.0.1+7" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.7" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.2" + uuid: + dependency: transitive + description: + name: uuid + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.0" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.0.8" + webview_flutter: + dependency: "direct main" + description: + name: webview_flutter + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.3.22+1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.1.0" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.6.1" +sdks: + dart: ">=2.8.0 <3.0.0" + flutter: ">=1.12.13+hotfix.5 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..5875161 --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,138 @@ +name: base_app +description: A new Flutter project. + +# The following line prevents the package from being accidentally published to +# pub.dev using `pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# 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 used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +version: 1.0.0+1 + +environment: + sdk: ">=2.7.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + flutter_localizations: + sdk: flutter + # iOS style icons. + cupertino_icons: ^0.1.3 + # Flutter 常用工具类库 https://github.com/Sky24n/flustars + flustars: ^0.3.2 + # toast + oktoast: ^2.1.7 + # http请求 + dio: 1.0.13 + # 数据库 + sqflite: ^1.3.0+2 + # 单图上传 + image_picker: ^0.6.7 + # 图片预览 + photo_view: ^0.9.2 + #非对称加密包 + encrypt: ^4.0.2 + # Flutter 城市列表 https://github.com/flutterchina/azlistview + azlistview: ^0.1.2 + # 汉字转拼音库 https://github.com/flutterchina/lpinyin + lpinyin: ^1.0.9 + # bloc用rxdart插件 https://github.com/ReactiveX/rxdart + rxdart: ^0.22.6 + # Flutter 国际化/多语言库 https://github.com/Sky24n/fluintl + fluintl: ^0.1.3 + # UI工具包含下拉刷新,轮播图,快速滚动条,渐变进度条,城市选择器等https://github.com/flutterchina/flukit. + flukit: ^1.0.2 + # 显示来自网络的图片并将它们保存在缓存 https://github.com/renefloor/flutter_cached_network_image + cached_network_image: 2.0.0 + # 拨电话、发邮件、打开网址、打开第三方 https://github.com/flutter/plugins/tree/master/packages/url_launcher + url_launcher: ^5.4.5 + # 分享share + share: ^0.6.4+1 + # webview_flutter + webview_flutter: ^0.3.21 + # 安装apk插件 + install_apk_plugin: ^1.0.1 + # 上拉加载和下拉刷新的组件 https://github.com/peng8350/flutter_pulltorefresh + pull_to_refresh: 1.1.6 + # 权限请求插件 + permission_handler: ^5.0.0+hotfix.6 + # 高德地图 + amap_map_fluttify: ^0.24.0+3 + + + +dev_dependencies: + flutter_test: + sdk: flutter + +# 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. +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 + + # To add assets to your application, add an assets section, like this: + assets: + - assets/images/ic_login_bg.png + - assets/images/guide1.png + - assets/images/guide2.png + - assets/images/guide3.png + - assets/images/splash_bg.png + - assets/images/default_avatar.jpg + - assets/images/logo.png + - assets/images/ic_data_empty.png + - assets/images/ic_network_error.png + - assets/images/qidian.png + - assets/images/zhongdian.png + - assets/images/jingshi.png + - assets/keys/public_key.pem + - assets/icons/camera.png + - assets/icons/card.png + - assets/icons/global.png + - assets/icons/image.png + - assets/icons/magic.png + - assets/icons/position.png + - assets/icons/scan.png + - assets/icons/setting.png + - assets/icons/warning.png + - assets/icons/text.png + + # 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: IconFont + fonts: + - asset: assets/font/iconfont.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 diff --git a/test/widget_test.dart b/test/widget_test.dart new file mode 100644 index 0000000..faa94f2 --- /dev/null +++ b/test/widget_test.dart @@ -0,0 +1,30 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility that Flutter provides. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:base_app/main.dart'; + +void main() { + testWidgets('Counter increments smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(MyApp()); // ����App��� + + // ��find���������Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); // ���������һ�� + expect(find.text('1'), findsNothing); // ���������0�� + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); // ģ�������� + await tester.pump(); // �ؽ���� + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +}